DragonFlyBSD Kernel Audit
DF-2694 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index bb26e999..88ffe7b7 100644
--- a/sys/kern/uipc_socket.c
+++ bb/sys/kern/uipc_socket.c
@@ -1966,11 +1966,35 @@ sorflush(struct socket *so)
 	struct signalsockbuf *ssb = &so->so_rcv;
 	struct protosw *pr = so->so_proto;
 	struct signalsockbuf asb;
+	int loops = 0;
 
 	atomic_set_int(&ssb->ssb_flags, SSB_NOINTR);
 
 	lwkt_gettoken(&ssb->ssb_token);
 	socantrcvmore(so);
+
+	/*
+	 * An active receiver (soreceive()/sorecvtcp(), including the
+	 * in-kernel sio consumers) holds SSB_LOCK across its entire
+	 * operation, including any sleeps inside uiomove() page faults.
+	 * A blocked thread temporarily releases its lwkt tokens, so the
+	 * token we hold does NOT protect the mbufs under a sleeping
+	 * copier: zeroing and freeing the sockbuf here would pull the
+	 * memory out from under it (UAF read + sockbuf invariant
+	 * breakage).  Give an active copier a bounded period of time to
+	 * finish its copy loop before we flush.
+	 *
+	 * socantrcvmore() above already woke readers blocked in
+	 * ssb_wait(), so MSG_WAITALL loops will terminate and release
+	 * SSB_LOCK; a copier blocked in a page fault completes
+	 * independently of us.
+	 */
+	while ((ssb->ssb_flags & SSB_LOCK) && loops++ < 1000) {
+		lwkt_reltoken(&ssb->ssb_token);
+		tsleep(&ssb->ssb_cc, 0, "soflush", 1);
+		lwkt_gettoken(&ssb->ssb_token);
+	}
+
 	asb = *ssb;
 
 	/*
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index 7b9322f4..ba7914b5 100644
--- a/sys/kern/uipc_syscalls.c
+++ bb/sys/kern/uipc_syscalls.c
@@ -1591,7 +1591,7 @@ sys_sendfile(struct sysmsg *sysmsg, const struct sendfile_args *uap)
 	size_t hbytes = 0;
 	size_t tbytes;
 	off_t hdtr_size = 0;
-	off_t sbytes;
+	off_t sbytes = 0;
 	int error;
 
 	/*