summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbms <bms@FreeBSD.org>2006-09-22 15:34:16 +0000
committerbms <bms@FreeBSD.org>2006-09-22 15:34:16 +0000
commitfdb36f8d074291fe047a05a5bdec3d633160c6ae (patch)
tree5162d04c3bd6dc1648577abc4bf465a0521acc3d
parentc8ba43b1fd77bb0b1f3d33613a8252ec2b9ca2e1 (diff)
downloadFreeBSD-src-fdb36f8d074291fe047a05a5bdec3d633160c6ae.zip
FreeBSD-src-fdb36f8d074291fe047a05a5bdec3d633160c6ae.tar.gz
Fix a case where socket I/O atomicity is violated due to not dropping
the entire record when a non-data mbuf is removed in the soreceive() path. This only triggers a panic directly when compiled with INVARIANTS. PR: 38495 Submitted by: James Juran MFC after: 1 week
-rw-r--r--sys/kern/uipc_socket.c17
1 files changed, 16 insertions, 1 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 480bde8..2a27388 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1405,6 +1405,7 @@ soreceive_generic(so, psa, uio, mp0, controlp, flagsp)
struct protosw *pr = so->so_proto;
struct mbuf *nextrecord;
int moff, type = 0;
+ int mbuf_removed = 0;
int orig_resid = uio->uio_resid;
mp = mp0;
@@ -1525,6 +1526,7 @@ dontblock:
m = m->m_next;
} else {
sbfree(&so->so_rcv, m);
+ mbuf_removed = 1;
so->so_rcv.sb_mb = m_free(m);
m = so->so_rcv.sb_mb;
sockbuf_pushsync(&so->so_rcv, nextrecord);
@@ -1550,6 +1552,7 @@ dontblock:
m = m->m_next;
} else {
sbfree(&so->so_rcv, m);
+ mbuf_removed = 1;
so->so_rcv.sb_mb = m->m_next;
m->m_next = NULL;
*cme = m;
@@ -1671,8 +1674,20 @@ dontblock:
#endif /* ZERO_COPY_SOCKETS */
error = uiomove(mtod(m, char *) + moff, (int)len, uio);
SOCKBUF_LOCK(&so->so_rcv);
- if (error)
+ if (error) {
+ /*
+ * If any part of the record has been removed
+ * (such as the MT_SONAME mbuf, which will
+ * happen when PR_ADDR, and thus also
+ * PR_ATOMIC, is set), then drop the entire
+ * record to maintain the atomicity of the
+ * receive operation.
+ */
+ if (m && mbuf_removed &&
+ (pr->pr_flags & PR_ATOMIC))
+ (void)sbdroprecord_locked(&so->so_rcv);
goto release;
+ }
} else
uio->uio_resid -= len;
SOCKBUF_LOCK_ASSERT(&so->so_rcv);
OpenPOWER on IntegriCloud