git: 69d79ceb2c01 - main - tests/unix_passfd: add test case against 636420bde36

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Fri, 30 Sep 2022 20:45:05 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=69d79ceb2c01931c129c5bafc300c33f3e106efd

commit 69d79ceb2c01931c129c5bafc300c33f3e106efd
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2022-09-30 20:41:41 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2022-09-30 20:43:37 +0000

    tests/unix_passfd: add test case against 636420bde36
---
 tests/sys/kern/unix_passfd_test.c | 72 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/tests/sys/kern/unix_passfd_test.c b/tests/sys/kern/unix_passfd_test.c
index 875201c4702e..92b8d73f2f4a 100644
--- a/tests/sys/kern/unix_passfd_test.c
+++ b/tests/sys/kern/unix_passfd_test.c
@@ -270,8 +270,10 @@ recvfd(int sockfd, int *recv_fd, int flags)
 
 #if TEST_PROTO == SOCK_STREAM
 #define	LOCAL_SENDSPACE_SYSCTL	"net.local.stream.sendspace"
+#define	LOCAL_RECVSPACE_SYSCTL	"net.local.stream.recvspace"
 #elif TEST_PROTO == SOCK_DGRAM
 #define	LOCAL_SENDSPACE_SYSCTL	"net.local.dgram.maxdgram"
+#define	LOCAL_RECVSPACE_SYSCTL	"net.local.dgram.recvspace"
 #endif
 
 static u_long
@@ -286,6 +288,46 @@ getsendspace(void)
 	return (sendspace);
 }
 
+static u_long
+getrecvspace(void)
+{
+	u_long recvspace;
+
+	ATF_REQUIRE_MSG(sysctlbyname(LOCAL_RECVSPACE_SYSCTL, &recvspace,
+            &(size_t){sizeof(u_long)}, NULL, 0) != -1,
+	    "sysctl %s failed: %s", LOCAL_RECVSPACE_SYSCTL, strerror(errno));
+
+	return (recvspace);
+}
+
+/*
+ * Fill socket to a state when next max sized send would fail with EAGAIN.
+ */
+static void
+fill(int fd)
+{
+	u_long sendspace;
+	void *buf;
+
+	sendspace = getsendspace();
+	ATF_REQUIRE((buf = malloc(sendspace)) != NULL);
+
+	ATF_REQUIRE_MSG(fcntl(fd, F_SETFL, O_NONBLOCK) != -1,
+	    "fcntl(O_NONBLOCK) failed: %s", strerror(errno));
+
+#if TEST_PROTO == SOCK_STREAM
+	do {} while (send(fd, buf, sendspace, 0) == (ssize_t)sendspace);
+#elif TEST_PROTO == SOCK_DGRAM
+	u_long recvspace = getrecvspace();
+
+	for (ssize_t sent = 0;
+	    sent + sendspace + sizeof(struct sockaddr) < recvspace;
+	    sent += sendspace + sizeof(struct sockaddr))
+		ATF_REQUIRE(send(fd, buf, sendspace, 0) == (ssize_t)sendspace);
+#endif
+	free(buf);
+}
+
 /*
  * Put a temporary file into a UNIX domain socket, then take it out and make
  * sure it's the same file.  First time around, don't close the reference
@@ -469,6 +511,35 @@ ATF_TC_BODY(send_a_lot, tc)
 #endif
 }
 
+/*
+ * Exersize condition when SCM_RIGHTS is successfully internalized, but
+ * message delivery fails due to receive buffer overflow.  Check that no
+ * file descriptors are leaked.
+ */
+ATF_TC_WITHOUT_HEAD(send_overflow);
+ATF_TC_BODY(send_overflow, tc)
+{
+	void *buf;
+	ssize_t len;
+	int fd[2], putfd, nfiles;
+	int sendspace;
+
+	sendspace = (int)getsendspace();
+	ATF_REQUIRE((buf = malloc(sendspace)) != NULL);
+
+	domainsocketpair(fd);
+	fill(fd[0]);
+	nfiles = openfiles();
+	tempfile(&putfd);
+	len = sendfd_payload(fd[0], putfd, buf, sendspace);
+	ATF_REQUIRE_MSG(len == -1 && errno == EAGAIN,
+	    "sendmsg: %zu bytes sent, errno %d", len, errno);
+	close(putfd);
+	ATF_REQUIRE(nfiles == openfiles());
+	closesocketpair(fd);
+}
+
+
 /*
  * Send two files.  Then receive them.  Make sure they are returned in the
  * right order, and both get there.
@@ -881,6 +952,7 @@ ATF_TP_ADD_TCS(tp)
 	ATF_TP_ADD_TC(tp, send_and_cancel);
 	ATF_TP_ADD_TC(tp, send_and_shutdown);
 	ATF_TP_ADD_TC(tp, send_a_lot);
+	ATF_TP_ADD_TC(tp, send_overflow);
 	ATF_TP_ADD_TC(tp, two_files);
 	ATF_TP_ADD_TC(tp, bundle);
 	ATF_TP_ADD_TC(tp, bundle_cancel);