Module Name:    src
Committed By:   riastradh
Date:           Thu Mar 27 11:01:07 UTC 2025

Modified Files:
        src/tests/net/net: t_unix.c

Log Message:
t_unix: Test LOCAL_CONNWAIT.

PR kern/59220: accept(2): null pointer deref


To generate a diff of this commit:
cvs rdiff -u -r1.27 -r1.28 src/tests/net/net/t_unix.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/tests/net/net/t_unix.c
diff -u src/tests/net/net/t_unix.c:1.27 src/tests/net/net/t_unix.c:1.28
--- src/tests/net/net/t_unix.c:1.27	Thu Mar 27 10:57:30 2025
+++ src/tests/net/net/t_unix.c	Thu Mar 27 11:01:07 2025
@@ -1,4 +1,4 @@
-/*	$NetBSD: t_unix.c,v 1.27 2025/03/27 10:57:30 riastradh Exp $	*/
+/*	$NetBSD: t_unix.c,v 1.28 2025/03/27 11:01:07 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -39,7 +39,7 @@
 #define _GNU_SOURCE
 #include <sys/cdefs.h>
 #ifdef __RCSID
-__RCSID("$Id: t_unix.c,v 1.27 2025/03/27 10:57:30 riastradh Exp $");
+__RCSID("$Id: t_unix.c,v 1.28 2025/03/27 11:01:07 riastradh Exp $");
 #else
 #define getprogname() argv[0]
 #endif
@@ -59,6 +59,7 @@ __RCSID("$Id: t_unix.c,v 1.27 2025/03/27
 
 #include <err.h>
 #include <errno.h>
+#include <poll.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -395,6 +396,8 @@ fail:
 
 #ifndef TEST
 
+#include "h_macros.h"
+
 ATF_TC(sockaddr_un_len_exceed);
 ATF_TC_HEAD(sockaddr_un_len_exceed, tc)
 {
@@ -439,6 +442,86 @@ ATF_TC_BODY(sockaddr_un_closed, tc)
 	    "test(false, true, false, 100): %s", strerror(errno));
 }
 
+ATF_TC(sockaddr_un_local_connwait);
+ATF_TC_HEAD(sockaddr_un_local_connwait, tc)
+{
+
+	atf_tc_set_md_var(tc, "descr", "Check that LOCAL_CONNWAIT works");
+}
+
+ATF_TC_BODY(sockaddr_un_local_connwait, tc)
+{
+	/* too annoying to fit this into the test(...) framework above */
+	struct sockaddr_un sun = {.sun_family = AF_UNIX, .sun_path = "sock"};
+	int listener, conn, acc;
+	const int one = 1;
+	struct pollfd pfd;
+	int nfd, error;
+	socklen_t errorlen = sizeof(error);
+
+	/*
+	 * Create and bind a listening socket.
+	 */
+	RL(listener = socket(PF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0));
+	RL(bind(listener, (const struct sockaddr *)&sun, sizeof(sun)));
+	RL(listen(listener, 5));
+
+	/*
+	 * Nobody's trying to connect, so accept would block.
+	 */
+	ATF_REQUIRE_ERRNO(EAGAIN, accept(listener, NULL, NULL) == -1);
+
+	/*
+	 * Connect should succeed immediately even though nobody is
+	 * waiting to accept on the other end yet.
+	 */
+	RL(conn = socket(PF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0));
+	RL(connect(conn, (const struct sockaddr *)&sun, sizeof(sun)));
+
+	/*
+	 * Accept should succeed now that a client connected.  Close
+	 * both sides; we're done with this connection and will try
+	 * again with LOCAL_CONNWAIT next.
+	 */
+	RL(acc = accept(listener, NULL, NULL));
+	RL(close(acc));
+	RL(close(conn));
+
+	/*
+	 * If we set LOCAL_CONNWAIT, connect should fail, but with
+	 * EINPROGRESS -- note: not EAGAIN, because it has changed
+	 * state.  If we try to connect again, it should fail with
+	 * EALREADY because the connection is already pending.
+	 */
+	RL(conn = socket(PF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0));
+	RL(setsockopt(conn, SOL_LOCAL, LOCAL_CONNWAIT, &one, sizeof(one)));
+	ATF_REQUIRE_ERRNO(EINPROGRESS,
+	    connect(conn, (const struct sockaddr *)&sun, sizeof(sun)) == -1);
+	ATF_REQUIRE_ERRNO(EALREADY,
+	    connect(conn, (const struct sockaddr *)&sun, sizeof(sun)) == -1);
+
+	/*
+	 * Accept should succeed immediately now.
+	 */
+	RL(acc = accept(listener, NULL, NULL));
+
+	/*
+	 * Verify via poll(2) that the pending connect(2) has finished
+	 * -- it will report POLLOUT when that happens.  And then
+	 * verify that there was no error.
+	 */
+	pfd = (struct pollfd){.fd = conn, .events = POLLOUT};
+	RL(nfd = poll(&pfd, 1, 0));
+	ATF_REQUIRE_MSG(pfd.revents & POLLOUT, "revents=0x%x", pfd.revents);
+	RL(getsockopt(conn, SOL_SOCKET, SO_ERROR, &error, &errorlen));
+	ATF_REQUIRE_MSG(errorlen == sizeof(error), "errorlen=%d", errorlen);
+	ATF_REQUIRE_MSG(error == 0, "error=%d", error);
+
+	RL(close(acc));
+	RL(close(conn));
+	RL(close(listener));
+}
+
 ATF_TC(sockaddr_un_local_peereid);
 ATF_TC_HEAD(sockaddr_un_local_peereid, tc)
 {
@@ -473,6 +556,7 @@ ATF_TP_ADD_TCS(tp)
 	ATF_TP_ADD_TC(tp, sockaddr_un_len_exceed);
 	ATF_TP_ADD_TC(tp, sockaddr_un_len_max);
 	ATF_TP_ADD_TC(tp, sockaddr_un_closed);
+	ATF_TP_ADD_TC(tp, sockaddr_un_local_connwait);
 	ATF_TP_ADD_TC(tp, sockaddr_un_local_peereid);
 	ATF_TP_ADD_TC(tp, sockaddr_un_fstat);
 	return atf_no_error();

Reply via email to