aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2025-11-13 22:56:15 +0000
committerMark Johnston <markj@FreeBSD.org>2025-11-14 00:43:38 +0000
commit9d9fa9a2c22f67d5f8afec18106c9f0072d6b3d4 (patch)
tree551fbc5a23fddd12524c07af78abb72add040697
parent477799750abd5702a02f7f8065e6235d7db75188 (diff)
unix: Fix handling of listening sockets during garbage collection
socantrcvmore() and unp_dispose() assume that the socket's socket buffers are initialized, which isn't the case for listening sockets. Reported by: syzbot+a62883292a5c257703be@syzkaller.appspotmail.com MFC after: 1 week Reviewed by: glebius Differential Revision: https://reviews.freebsd.org/D53743
-rw-r--r--sys/kern/uipc_usrreq.c10
-rw-r--r--tests/sys/kern/unix_passfd_test.c29
2 files changed, 35 insertions, 4 deletions
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index 807271488af2..8c9fa4c012e4 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -4208,10 +4208,12 @@ unp_gc(__unused void *arg, int pending)
struct socket *so;
so = unref[i]->f_data;
- CURVNET_SET(so->so_vnet);
- socantrcvmore(so);
- unp_dispose(so);
- CURVNET_RESTORE();
+ if (!SOLISTENING(so)) {
+ CURVNET_SET(so->so_vnet);
+ socantrcvmore(so);
+ unp_dispose(so);
+ CURVNET_RESTORE();
+ }
}
/*
diff --git a/tests/sys/kern/unix_passfd_test.c b/tests/sys/kern/unix_passfd_test.c
index 7dc4541ad402..66bb406ea14e 100644
--- a/tests/sys/kern/unix_passfd_test.c
+++ b/tests/sys/kern/unix_passfd_test.c
@@ -1189,6 +1189,34 @@ ATF_TC_CLEANUP(cross_jail_dirfd, tc)
err(1, "jail_remove");
}
+ATF_TC_WITHOUT_HEAD(listening_socket);
+ATF_TC_BODY(listening_socket, tc)
+{
+ struct sockaddr_un sun;
+ int error, ls, s[2];
+
+ ls = socket(AF_UNIX, SOCK_STREAM, 0);
+ ATF_REQUIRE(ls != -1);
+
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_len = sizeof(sun);
+ sun.sun_family = AF_UNIX;
+ snprintf(sun.sun_path, sizeof(sun.sun_path), "listen.sock");
+ error = bind(ls, (struct sockaddr *)&sun, sizeof(sun));
+ ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
+ error = listen(ls, 0);
+
+ error = socketpair(AF_UNIX, SOCK_STREAM, 0, s);
+ ATF_REQUIRE_MSG(error == 0, "socketpair failed: %s", strerror(errno));
+
+ sendfd(s[0], ls);
+ sendfd(s[0], s[0]);
+ sendfd(s[0], s[1]);
+ close(ls);
+ close(s[0]);
+ close(s[1]);
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -1211,6 +1239,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, empty_rights_message);
ATF_TP_ADD_TC(tp, control_creates_records);
ATF_TP_ADD_TC(tp, cross_jail_dirfd);
+ ATF_TP_ADD_TC(tp, listening_socket);
return (atf_no_error());
}