summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcmetz <cmetz@openbsd.org>1999-10-14 08:18:49 +0000
committercmetz <cmetz@openbsd.org>1999-10-14 08:18:49 +0000
commitb8502fcbfaae718620e5a5593d4e70b08c067daf (patch)
treefb0f4de8c8ff89f56f0ce40f2673a601d66a8988
parentread disklabels only from CDs that have a data track, spoofed labels from (diff)
downloadwireguard-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.c22
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;