Update PR 131876 regression tests after r337423.
- Add some more cases to the truncation test. - Remove the "expect fail" annotations. PR: 131876 MFC after: 1 month Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D16562
This commit is contained in:
parent
c7902fbeae
commit
ffb8b43ec2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=337424
@ -118,6 +118,20 @@ getnfds(void)
|
||||
return (n);
|
||||
}
|
||||
|
||||
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 @@ sendfd_payload(int sockfd, int send_fd, void *payload, size_t paylen)
|
||||
{
|
||||
struct iovec iovec;
|
||||
char message[CMSG_SPACE(sizeof(int))];
|
||||
struct cmsghdr *cmsghdr;
|
||||
struct msghdr msghdr;
|
||||
ssize_t len;
|
||||
|
||||
@ -147,13 +160,8 @@ sendfd_payload(int sockfd, int send_fd, void *payload, size_t paylen)
|
||||
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 @@ localcreds(int sockfd)
|
||||
}
|
||||
|
||||
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 @@ recvfd(int sockfd, int *recv_fd)
|
||||
{
|
||||
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 @@ ATF_TC_BODY(rights_creds_payload, tc)
|
||||
|
||||
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));
|
||||
|
||||
bzero(&msghdr, sizeof(msghdr));
|
||||
bzero(message, sizeof(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;
|
||||
|
||||
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");
|
||||
|
||||
ATF_REQUIRE_MSG((msghdr.msg_flags & MSG_CTRUNC) != 0,
|
||||
"MSG_CTRUNC not set after truncation");
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
@ -486,9 +591,6 @@ ATF_TC_BODY(copyout_rights_error, tc)
|
||||
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);
|
||||
devnull(&putfd);
|
||||
|
Loading…
Reference in New Issue
Block a user