Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F111866424
D16562.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D16562.diff
View Options
Index: head/tests/sys/kern/unix_passfd_test.c
===================================================================
--- head/tests/sys/kern/unix_passfd_test.c
+++ head/tests/sys/kern/unix_passfd_test.c
@@ -119,6 +119,20 @@
}
static void
+putfds(char *buf, int fd, int nfds)
+{
+ struct cmsghdr *cm;
+ int *fdp, i;
+
+ cm = (struct cmsghdr *)buf;
+ cm->cmsg_len = CMSG_LEN(nfds * sizeof(int));
+ cm->cmsg_level = SOL_SOCKET;
+ cm->cmsg_type = SCM_RIGHTS;
+ for (fdp = (int *)CMSG_DATA(cm), i = 0; i < nfds; i++)
+ *fdp++ = fd;
+}
+
+static void
samefile(struct stat *sb1, struct stat *sb2)
{
@@ -131,7 +145,6 @@
{
struct iovec iovec;
char message[CMSG_SPACE(sizeof(int))];
- struct cmsghdr *cmsghdr;
struct msghdr msghdr;
ssize_t len;
@@ -147,13 +160,8 @@
msghdr.msg_iov = &iovec;
msghdr.msg_iovlen = 1;
- cmsghdr = (struct cmsghdr *)(void *)message;
- cmsghdr->cmsg_len = CMSG_LEN(sizeof(int));
- cmsghdr->cmsg_level = SOL_SOCKET;
- cmsghdr->cmsg_type = SCM_RIGHTS;
- memcpy(CMSG_DATA(cmsghdr), &send_fd, sizeof(int));
-
- len = sendmsg(sockfd, &msghdr, MSG_DONTWAIT);
+ putfds(message, send_fd, 1);
+ len = sendmsg(sockfd, &msghdr, 0);
ATF_REQUIRE_MSG(len != -1, "sendmsg failed: %s", strerror(errno));
return ((size_t)len);
}
@@ -185,20 +193,22 @@
}
static void
-recvfd_payload(int sockfd, int *recv_fd, void *buf, size_t buflen)
+recvfd_payload(int sockfd, int *recv_fd, void *buf, size_t buflen,
+ size_t cmsgsz)
{
struct cmsghdr *cmsghdr;
- char message[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) +
- CMSG_SPACE(sizeof(int))];
struct msghdr msghdr;
struct iovec iovec;
+ char *message;
ssize_t len;
bool foundcreds;
bzero(&msghdr, sizeof(msghdr));
+ message = malloc(cmsgsz);
+ ATF_REQUIRE(message != NULL);
msghdr.msg_control = message;
- msghdr.msg_controllen = sizeof(message);
+ msghdr.msg_controllen = cmsgsz;
iovec.iov_base = buf;
iovec.iov_len = buflen;
@@ -237,7 +247,8 @@
{
char ch = 0;
- recvfd_payload(sockfd, recv_fd, &ch, sizeof(ch));
+ recvfd_payload(sockfd, recv_fd, &ch, sizeof(ch),
+ CMSG_SPACE(sizeof(int)));
}
/*
@@ -418,65 +429,159 @@
len = sendfd_payload(fd[0], putfd, buf, sendspace);
ATF_REQUIRE_MSG(len < sendspace, "sendmsg: %zu bytes sent", len);
- recvfd_payload(fd[1], &getfd, buf, len);
+ recvfd_payload(fd[1], &getfd, buf, len,
+ CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + CMSG_SPACE(sizeof(int)));
close(putfd);
close(getfd);
closesocketpair(fd);
}
+static void
+send_cmsg(int sockfd, void *cmsg, size_t cmsgsz)
+{
+ struct iovec iov;
+ struct msghdr msghdr;
+ ssize_t len;
+ char ch;
+
+ ch = 0;
+ bzero(&msghdr, sizeof(msghdr));
+
+ iov.iov_base = &ch;
+ iov.iov_len = sizeof(ch);
+ msghdr.msg_control = cmsg;
+ msghdr.msg_controllen = cmsgsz;
+ msghdr.msg_iov = &iov;
+ msghdr.msg_iovlen = 1;
+
+ len = sendmsg(sockfd, &msghdr, 0);
+ ATF_REQUIRE_MSG(len != -1,
+ "sendmsg failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(len == sizeof(ch),
+ "sendmsg: %zd bytes sent; expected %zu", len, sizeof(ch));
+}
+
+static void
+recv_cmsg(int sockfd, char *cmsg, size_t cmsgsz, int flags)
+{
+ struct iovec iov;
+ struct msghdr msghdr;
+ ssize_t len;
+ char ch;
+
+ ch = 0;
+ bzero(&msghdr, sizeof(msghdr));
+
+ iov.iov_base = &ch;
+ iov.iov_len = sizeof(ch);
+ msghdr.msg_control = cmsg;
+ msghdr.msg_controllen = cmsgsz;
+ msghdr.msg_iov = &iov;
+ msghdr.msg_iovlen = 1;
+
+ len = recvmsg(sockfd, &msghdr, 0);
+ ATF_REQUIRE_MSG(len != -1,
+ "recvmsg failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(len == sizeof(ch),
+ "recvmsg: %zd bytes received; expected %zu", len, sizeof(ch));
+ ATF_REQUIRE_MSG((msghdr.msg_flags & flags) == flags,
+ "recvmsg: got flags %#x; expected %#x", msghdr.msg_flags, flags);
+}
+
/*
- * Test for PR 131876. Receiver uses a control message buffer that is too
+ * Test for PR 131876. Receiver uses a control message buffer that is too
* small for the incoming SCM_RIGHTS message, so the message is truncated.
* The kernel must not leak the copied right into the receiver's namespace.
*/
ATF_TC_WITHOUT_HEAD(truncated_rights);
ATF_TC_BODY(truncated_rights, tc)
{
- struct iovec iovec;
- struct msghdr msghdr;
- char buf[16], message[CMSG_SPACE(0)];
- ssize_t len;
- int fd[2], nfds, putfd;
+ char *message;
+ int fd[2], nfds, putfd, rc;
- atf_tc_expect_fail("PR 131876: "
- "FD leak when 'control' message is truncated");
-
- memset(buf, 42, sizeof(buf));
domainsocketpair(fd);
devnull(&putfd);
nfds = getnfds();
- len = sendfd_payload(fd[0], putfd, buf, sizeof(buf));
- ATF_REQUIRE_MSG(len == sizeof(buf),
- "sendmsg: %zd bytes sent; expected %zu; %s", len, sizeof(buf),
- strerror(errno));
+ /*
+ * Case 1: Send a single descriptor and truncate the message.
+ */
+ message = malloc(CMSG_SPACE(sizeof(int)));
+ ATF_REQUIRE(message != NULL);
+ putfds(message, putfd, 1);
+ send_cmsg(fd[0], message, CMSG_LEN(sizeof(int)));
+ recv_cmsg(fd[1], message, CMSG_LEN(0), MSG_CTRUNC);
+ ATF_REQUIRE(getnfds() == nfds);
+ free(message);
- bzero(&msghdr, sizeof(msghdr));
- bzero(message, sizeof(message));
+ /*
+ * Case 2a: Send two descriptors in separate messages, and truncate at
+ * the boundary between the two messages. We should still
+ * receive the first message.
+ */
+ message = malloc(CMSG_SPACE(sizeof(int)) * 2);
+ ATF_REQUIRE(message != NULL);
+ putfds(message, putfd, 1);
+ putfds(message + CMSG_SPACE(sizeof(int)), putfd, 1);
+ send_cmsg(fd[0], message, CMSG_SPACE(sizeof(int)) * 2);
+ recv_cmsg(fd[1], message, CMSG_SPACE(sizeof(int)), MSG_CTRUNC);
+ rc = close(*(int *)CMSG_DATA(message));
+ ATF_REQUIRE_MSG(rc == 0, "close failed: %s", strerror(errno));
+ ATF_REQUIRE(getnfds() == nfds);
+ free(message);
- iovec.iov_base = buf;
- iovec.iov_len = sizeof(buf);
- msghdr.msg_control = message;
- msghdr.msg_controllen = sizeof(message);
- msghdr.msg_iov = &iovec;
- msghdr.msg_iovlen = 1;
+ /*
+ * Case 2b: Send two descriptors in separate messages, and truncate
+ * before the end of the first message.
+ */
+ message = malloc(CMSG_SPACE(sizeof(int)) * 2);
+ ATF_REQUIRE(message != NULL);
+ putfds(message, putfd, 1);
+ putfds(message + CMSG_SPACE(sizeof(int)), putfd, 1);
+ send_cmsg(fd[0], message, CMSG_SPACE(sizeof(int)) * 2);
+ recv_cmsg(fd[1], message, CMSG_SPACE(0), MSG_CTRUNC);
+ ATF_REQUIRE(getnfds() == nfds);
+ free(message);
- len = recvmsg(fd[1], &msghdr, 0);
- ATF_REQUIRE_MSG(len != -1, "recvmsg failed: %s", strerror(errno));
- ATF_REQUIRE_MSG((size_t)len == sizeof(buf),
- "recvmsg: %zd bytes received; expected %zd", len, sizeof(buf));
- for (size_t i = 0; i < sizeof(buf); i++)
- ATF_REQUIRE_MSG(buf[i] == 42, "unexpected buffer contents");
+ /*
+ * Case 2c: Send two descriptors in separate messages, and truncate
+ * after the end of the first message. We should still
+ * receive the first message.
+ */
+ message = malloc(CMSG_SPACE(sizeof(int)) * 2);
+ ATF_REQUIRE(message != NULL);
+ putfds(message, putfd, 1);
+ putfds(message + CMSG_SPACE(sizeof(int)), putfd, 1);
+ send_cmsg(fd[0], message, CMSG_SPACE(sizeof(int)) * 2);
+ recv_cmsg(fd[1], message, CMSG_SPACE(sizeof(int)) + CMSG_SPACE(0),
+ MSG_CTRUNC);
+ rc = close(*(int *)CMSG_DATA(message));
+ ATF_REQUIRE_MSG(rc == 0, "close failed: %s", strerror(errno));
+ ATF_REQUIRE(getnfds() == nfds);
+ free(message);
- ATF_REQUIRE_MSG((msghdr.msg_flags & MSG_CTRUNC) != 0,
- "MSG_CTRUNC not set after truncation");
+ /*
+ * Case 3: Send three descriptors in the same message, and leave space
+ * only for the first when receiving the message.
+ */
+ message = malloc(CMSG_SPACE(sizeof(int) * 3));
+ ATF_REQUIRE(message != NULL);
+ putfds(message, putfd, 3);
+ send_cmsg(fd[0], message, CMSG_SPACE(sizeof(int) * 3));
+ recv_cmsg(fd[1], message, CMSG_SPACE(sizeof(int)), MSG_CTRUNC);
ATF_REQUIRE(getnfds() == nfds);
+ free(message);
close(putfd);
closesocketpair(fd);
}
+/*
+ * Ensure that an attempt to copy a SCM_RIGHTS message to the recipient
+ * fails. In this case the kernel must dispose of the externalized rights
+ * rather than leaking them into the recipient's file descriptor table.
+ */
ATF_TC_WITHOUT_HEAD(copyout_rights_error);
ATF_TC_BODY(copyout_rights_error, tc)
{
@@ -485,9 +590,6 @@
char buf[16];
ssize_t len;
int fd[2], error, nfds, putfd;
-
- atf_tc_expect_fail("PR 131876: "
- "FD leak when copyout of rights returns an error");
memset(buf, 0, sizeof(buf));
domainsocketpair(fd);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Mar 10, 1:11 PM (16 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17084450
Default Alt Text
D16562.diff (8 KB)
Attached To
Mode
D16562: Add some regression tests for control message truncation.
Attached
Detach File
Event Timeline
Log In to Comment