DF-2694 / fix.diff
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; /* |