diff options
author | 1999-10-14 08:18:49 +0000 | |
---|---|---|
committer | 1999-10-14 08:18:49 +0000 | |
commit | b8502fcbfaae718620e5a5593d4e70b08c067daf (patch) | |
tree | fb0f4de8c8ff89f56f0ce40f2673a601d66a8988 | |
parent | read disklabels only from CDs that have a data track, spoofed labels from (diff) | |
download | wireguard-openbsd-b8502fcbfaae718620e5a5593d4e70b08c067daf.tar.xz wireguard-openbsd-b8502fcbfaae718620e5a5593d4e70b08c067daf.zip |
Fix for PR 871.
This fix is taken from BSD/OS (the file in question being BSD licensed).
It continues to remove a datagram from a socket receive buffer even if there is
an error on the copy-out, so as to leave the buffer in a reasonable state.
Before, the kernel would stop in mid-receive if the copy-out failed, and the
buffer's structural requirements would be violated (since the start of a
datagram must be an address iff ).
Note that if the user provides any invalid addresses as arguments to a
recvmsg(), the datagram at the front of the buffer will be discarded. The more
correct behavior would be not to remove this datagram if the arguments are
invalid. Implementing this behavior requires a lot of significant changes, and
socket receives are a critical path.
Also included are two simple and fairly obvious fixes from the same source.
If non-blocking I/O is set, it makes sure the receieve is non-blocking. It also
fixes a slightly over-aggressive optimization.
-rw-r--r-- | sys/kern/uipc_socket.c | 22 |
1 files changed, 16 insertions, 6 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index b5534ca0835..3dce36b6462 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_socket.c,v 1.26 1999/02/19 15:06:52 millert Exp $ */ +/* $OpenBSD: uipc_socket.c,v 1.27 1999/10/14 08:18:49 cmetz Exp $ */ /* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */ /* @@ -536,6 +536,8 @@ soreceive(so, paddr, uio, mp0, controlp, flagsp) struct mbuf *nextrecord; int moff, type = 0; size_t orig_resid = uio->uio_resid; + int uio_error = 0; + int resid; mp = mp0; if (paddr) @@ -546,6 +548,8 @@ soreceive(so, paddr, uio, mp0, controlp, flagsp) flags = *flagsp &~ MSG_EOR; else flags = 0; + if (so->so_state & SS_NBIO) + flags |= MSG_DONTWAIT; if (flags & MSG_OOB) { m = m_get(M_WAIT, MT_DATA); error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m, @@ -617,7 +621,7 @@ restart: error = ENOTCONN; goto release; } - if (uio->uio_resid == 0) + if (uio->uio_resid == 0 && controlp == NULL) goto release; if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { error = EWOULDBLOCK; @@ -722,12 +726,15 @@ dontblock: * we must note any additions to the sockbuf when we * block interrupts again. */ - if (mp == 0) { + if (mp == 0 && uio_error == 0) { + resid = uio->uio_resid; splx(s); - error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); + uio_error = + uiomove(mtod(m, caddr_t) + moff, (int)len, + uio); s = splsoftnet(); - if (error) - goto release; + if (uio_error) + uio->uio_resid = resid - len; } else uio->uio_resid -= len; if (len == m->m_len - moff) { @@ -817,6 +824,9 @@ dontblock: splx(s); goto restart; } + + if (uio_error) + error = uio_error; if (flagsp) *flagsp |= flags; |