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
@ -118,6 +118,20 @@ getnfds(void)
|
|||||||
return (n);
|
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
|
static void
|
||||||
samefile(struct stat *sb1, struct stat *sb2)
|
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;
|
struct iovec iovec;
|
||||||
char message[CMSG_SPACE(sizeof(int))];
|
char message[CMSG_SPACE(sizeof(int))];
|
||||||
struct cmsghdr *cmsghdr;
|
|
||||||
struct msghdr msghdr;
|
struct msghdr msghdr;
|
||||||
ssize_t len;
|
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_iov = &iovec;
|
||||||
msghdr.msg_iovlen = 1;
|
msghdr.msg_iovlen = 1;
|
||||||
|
|
||||||
cmsghdr = (struct cmsghdr *)(void *)message;
|
putfds(message, send_fd, 1);
|
||||||
cmsghdr->cmsg_len = CMSG_LEN(sizeof(int));
|
len = sendmsg(sockfd, &msghdr, 0);
|
||||||
cmsghdr->cmsg_level = SOL_SOCKET;
|
|
||||||
cmsghdr->cmsg_type = SCM_RIGHTS;
|
|
||||||
memcpy(CMSG_DATA(cmsghdr), &send_fd, sizeof(int));
|
|
||||||
|
|
||||||
len = sendmsg(sockfd, &msghdr, MSG_DONTWAIT);
|
|
||||||
ATF_REQUIRE_MSG(len != -1, "sendmsg failed: %s", strerror(errno));
|
ATF_REQUIRE_MSG(len != -1, "sendmsg failed: %s", strerror(errno));
|
||||||
return ((size_t)len);
|
return ((size_t)len);
|
||||||
}
|
}
|
||||||
@ -185,20 +193,22 @@ localcreds(int sockfd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
struct cmsghdr *cmsghdr;
|
||||||
char message[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) +
|
|
||||||
CMSG_SPACE(sizeof(int))];
|
|
||||||
struct msghdr msghdr;
|
struct msghdr msghdr;
|
||||||
struct iovec iovec;
|
struct iovec iovec;
|
||||||
|
char *message;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
bool foundcreds;
|
bool foundcreds;
|
||||||
|
|
||||||
bzero(&msghdr, sizeof(msghdr));
|
bzero(&msghdr, sizeof(msghdr));
|
||||||
|
message = malloc(cmsgsz);
|
||||||
|
ATF_REQUIRE(message != NULL);
|
||||||
|
|
||||||
msghdr.msg_control = message;
|
msghdr.msg_control = message;
|
||||||
msghdr.msg_controllen = sizeof(message);
|
msghdr.msg_controllen = cmsgsz;
|
||||||
|
|
||||||
iovec.iov_base = buf;
|
iovec.iov_base = buf;
|
||||||
iovec.iov_len = buflen;
|
iovec.iov_len = buflen;
|
||||||
@ -237,7 +247,8 @@ recvfd(int sockfd, int *recv_fd)
|
|||||||
{
|
{
|
||||||
char ch = 0;
|
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);
|
len = sendfd_payload(fd[0], putfd, buf, sendspace);
|
||||||
ATF_REQUIRE_MSG(len < sendspace, "sendmsg: %zu bytes sent", len);
|
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(putfd);
|
||||||
close(getfd);
|
close(getfd);
|
||||||
closesocketpair(fd);
|
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.
|
* 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.
|
* The kernel must not leak the copied right into the receiver's namespace.
|
||||||
*/
|
*/
|
||||||
ATF_TC_WITHOUT_HEAD(truncated_rights);
|
ATF_TC_WITHOUT_HEAD(truncated_rights);
|
||||||
ATF_TC_BODY(truncated_rights, tc)
|
ATF_TC_BODY(truncated_rights, tc)
|
||||||
{
|
{
|
||||||
struct iovec iovec;
|
char *message;
|
||||||
struct msghdr msghdr;
|
int fd[2], nfds, putfd, rc;
|
||||||
char buf[16], message[CMSG_SPACE(0)];
|
|
||||||
ssize_t len;
|
|
||||||
int fd[2], nfds, putfd;
|
|
||||||
|
|
||||||
atf_tc_expect_fail("PR 131876: "
|
|
||||||
"FD leak when 'control' message is truncated");
|
|
||||||
|
|
||||||
memset(buf, 42, sizeof(buf));
|
|
||||||
domainsocketpair(fd);
|
domainsocketpair(fd);
|
||||||
devnull(&putfd);
|
devnull(&putfd);
|
||||||
nfds = getnfds();
|
nfds = getnfds();
|
||||||
|
|
||||||
len = sendfd_payload(fd[0], putfd, buf, sizeof(buf));
|
/*
|
||||||
ATF_REQUIRE_MSG(len == sizeof(buf),
|
* Case 1: Send a single descriptor and truncate the message.
|
||||||
"sendmsg: %zd bytes sent; expected %zu; %s", len, sizeof(buf),
|
*/
|
||||||
strerror(errno));
|
message = malloc(CMSG_SPACE(sizeof(int)));
|
||||||
|
ATF_REQUIRE(message != NULL);
|
||||||
bzero(&msghdr, sizeof(msghdr));
|
putfds(message, putfd, 1);
|
||||||
bzero(message, sizeof(message));
|
send_cmsg(fd[0], message, CMSG_LEN(sizeof(int)));
|
||||||
|
recv_cmsg(fd[1], message, CMSG_LEN(0), MSG_CTRUNC);
|
||||||
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");
|
|
||||||
ATF_REQUIRE(getnfds() == nfds);
|
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);
|
close(putfd);
|
||||||
closesocketpair(fd);
|
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_WITHOUT_HEAD(copyout_rights_error);
|
||||||
ATF_TC_BODY(copyout_rights_error, tc)
|
ATF_TC_BODY(copyout_rights_error, tc)
|
||||||
{
|
{
|
||||||
@ -486,9 +591,6 @@ ATF_TC_BODY(copyout_rights_error, tc)
|
|||||||
ssize_t len;
|
ssize_t len;
|
||||||
int fd[2], error, nfds, putfd;
|
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));
|
memset(buf, 0, sizeof(buf));
|
||||||
domainsocketpair(fd);
|
domainsocketpair(fd);
|
||||||
devnull(&putfd);
|
devnull(&putfd);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user