The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=c44d6f43a68f6bb39b92df85c5ba90a9b0feee15
commit c44d6f43a68f6bb39b92df85c5ba90a9b0feee15 Author: Gleb Smirnoff <gleb...@freebsd.org> AuthorDate: 2025-05-12 18:12:09 +0000 Commit: Gleb Smirnoff <gleb...@freebsd.org> CommitDate: 2025-05-23 22:04:38 +0000 unix/stream: provide uipc_cantrcvmore() and use it the pr_shutdown method. While unix/dgram can still use generic socket socantrcvmore(), the stream versions need a specific one. This fixes a panic reported by syzkaller. While here inline unp_shutdown() into uipc_shutdown(). Reported-by: syzbot+86c18f0886f70a350...@syzkaller.appspotmail.com --- sys/kern/uipc_usrreq.c | 52 +++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index a855c47d2e5a..0f730cf9424b 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -299,7 +299,6 @@ static int unp_connectat(int, struct socket *, struct sockaddr *, static void unp_connect2(struct socket *, struct socket *, bool); static void unp_disconnect(struct unpcb *unp, struct unpcb *unp2); static void unp_dispose(struct socket *so); -static void unp_shutdown(struct unpcb *); static void unp_drop(struct unpcb *); static void unp_gc(__unused void *, int); static void unp_scan(struct mbuf *, void (*)(struct filedescent **, int)); @@ -1341,6 +1340,18 @@ uipc_wakeup(struct socket *so) SOCK_RECVBUF_UNLOCK(so); } +static void +uipc_cantrcvmore(struct socket *so) +{ + + SOCK_RECVBUF_LOCK(so); + so->so_rcv.sb_state |= SBS_CANTRCVMORE; + if (so->so_rcv.uxst_peer != NULL) + uipc_wakeup(so); + else + SOCK_RECVBUF_UNLOCK(so); +} + static int uipc_soreceive_stream_or_seqpacket(struct socket *so, struct sockaddr **psa, struct uio *uio, struct mbuf **mp0, struct mbuf **controlp, int *flagsp) @@ -2646,18 +2657,28 @@ uipc_shutdown(struct socket *so, enum shutdown_how how) switch (how) { case SHUT_RD: - socantrcvmore(so); + if (so->so_type == SOCK_DGRAM) + socantrcvmore(so); + else + uipc_cantrcvmore(so); unp_dispose(so); break; case SHUT_RDWR: - socantrcvmore(so); + if (so->so_type == SOCK_DGRAM) + socantrcvmore(so); + else + uipc_cantrcvmore(so); unp_dispose(so); /* FALLTHROUGH */ case SHUT_WR: - UNP_PCB_LOCK(unp); - socantsendmore(so); - unp_shutdown(unp); - UNP_PCB_UNLOCK(unp); + if (so->so_type == SOCK_DGRAM) { + socantsendmore(so); + } else { + UNP_PCB_LOCK(unp); + if (unp->unp_conn != NULL) + uipc_cantrcvmore(unp->unp_conn->unp_socket); + UNP_PCB_UNLOCK(unp); + } } wakeup(&so->so_timeo); @@ -3380,23 +3401,6 @@ SYSCTL_PROC(_net_local_seqpacket, OID_AUTO, pcblist, (void *)(intptr_t)SOCK_SEQPACKET, 0, unp_pcblist, "S,xunpcb", "List of active local seqpacket sockets"); -static void -unp_shutdown(struct unpcb *unp) -{ - struct unpcb *unp2; - struct socket *so; - - UNP_PCB_LOCK_ASSERT(unp); - - unp2 = unp->unp_conn; - if ((unp->unp_socket->so_type == SOCK_STREAM || - (unp->unp_socket->so_type == SOCK_SEQPACKET)) && unp2 != NULL) { - so = unp2->unp_socket; - if (so != NULL) - socantrcvmore(so); - } -} - static void unp_drop(struct unpcb *unp) {