Changeset View
Changeset View
Standalone View
Standalone View
head/tests/sys/kern/unix_passfd_test.c
Show First 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
samefile(struct stat *sb1, struct stat *sb2) | samefile(struct stat *sb1, struct stat *sb2) | ||||
{ | { | ||||
ATF_REQUIRE_MSG(sb1->st_dev == sb2->st_dev, "different device"); | ATF_REQUIRE_MSG(sb1->st_dev == sb2->st_dev, "different device"); | ||||
ATF_REQUIRE_MSG(sb1->st_ino == sb2->st_ino, "different inode"); | ATF_REQUIRE_MSG(sb1->st_ino == sb2->st_ino, "different inode"); | ||||
} | } | ||||
static void | static size_t | ||||
sendfd_payload(int sockfd, int send_fd, void *payload, size_t paylen) | 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 cmsghdr *cmsghdr; | ||||
struct msghdr msghdr; | struct msghdr msghdr; | ||||
ssize_t len; | ssize_t len; | ||||
Show All 10 Lines | sendfd_payload(int sockfd, int send_fd, void *payload, size_t paylen) | ||||
msghdr.msg_iovlen = 1; | msghdr.msg_iovlen = 1; | ||||
cmsghdr = (struct cmsghdr *)(void *)message; | cmsghdr = (struct cmsghdr *)(void *)message; | ||||
cmsghdr->cmsg_len = CMSG_LEN(sizeof(int)); | cmsghdr->cmsg_len = CMSG_LEN(sizeof(int)); | ||||
cmsghdr->cmsg_level = SOL_SOCKET; | cmsghdr->cmsg_level = SOL_SOCKET; | ||||
cmsghdr->cmsg_type = SCM_RIGHTS; | cmsghdr->cmsg_type = SCM_RIGHTS; | ||||
memcpy(CMSG_DATA(cmsghdr), &send_fd, sizeof(int)); | memcpy(CMSG_DATA(cmsghdr), &send_fd, sizeof(int)); | ||||
len = sendmsg(sockfd, &msghdr, 0); | 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)); | ||||
ATF_REQUIRE_MSG((size_t)len == paylen, | return ((size_t)len); | ||||
"sendmsg: %zd messages sent; expected: %zu; %s", len, paylen, | |||||
strerror(errno)); | |||||
} | } | ||||
static void | static void | ||||
sendfd(int sockfd, int send_fd) | sendfd(int sockfd, int send_fd) | ||||
{ | { | ||||
char ch = 0; | size_t len; | ||||
char ch; | |||||
sendfd_payload(sockfd, send_fd, &ch, sizeof(ch)); | ch = 0; | ||||
len = sendfd_payload(sockfd, send_fd, &ch, sizeof(ch)); | |||||
ATF_REQUIRE_MSG(len == sizeof(ch), | |||||
"sendmsg: %zu bytes sent; expected %zu; %s", len, sizeof(ch), | |||||
strerror(errno)); | |||||
} | } | ||||
static bool | |||||
localcreds(int sockfd) | |||||
{ | |||||
socklen_t sz; | |||||
int rc, val; | |||||
sz = sizeof(val); | |||||
rc = getsockopt(sockfd, 0, LOCAL_CREDS, &val, &sz); | |||||
ATF_REQUIRE_MSG(rc != -1, "getsockopt(LOCAL_CREDS) failed: %s", | |||||
strerror(errno)); | |||||
return (val != 0); | |||||
} | |||||
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) | ||||
{ | { | ||||
struct cmsghdr *cmsghdr; | struct cmsghdr *cmsghdr; | ||||
char message[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + | char message[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + | ||||
CMSG_SPACE(sizeof(int))]; | CMSG_SPACE(sizeof(int))]; | ||||
struct msghdr msghdr; | struct msghdr msghdr; | ||||
struct iovec iovec; | struct iovec iovec; | ||||
ssize_t len; | ssize_t len; | ||||
bool foundcreds; | |||||
bzero(&msghdr, sizeof(msghdr)); | bzero(&msghdr, sizeof(msghdr)); | ||||
msghdr.msg_control = message; | msghdr.msg_control = message; | ||||
msghdr.msg_controllen = sizeof(message); | msghdr.msg_controllen = sizeof(message); | ||||
iovec.iov_base = buf; | iovec.iov_base = buf; | ||||
iovec.iov_len = buflen; | iovec.iov_len = buflen; | ||||
msghdr.msg_iov = &iovec; | msghdr.msg_iov = &iovec; | ||||
msghdr.msg_iovlen = 1; | msghdr.msg_iovlen = 1; | ||||
len = recvmsg(sockfd, &msghdr, 0); | len = recvmsg(sockfd, &msghdr, 0); | ||||
ATF_REQUIRE_MSG(len != -1, "recvmsg failed: %s", strerror(errno)); | ATF_REQUIRE_MSG(len != -1, "recvmsg failed: %s", strerror(errno)); | ||||
ATF_REQUIRE_MSG((size_t)len == buflen, | ATF_REQUIRE_MSG((size_t)len == buflen, | ||||
"recvmsg: %zd bytes received; expected %zd", len, buflen); | "recvmsg: %zd bytes received; expected %zd", len, buflen); | ||||
cmsghdr = CMSG_FIRSTHDR(&msghdr); | cmsghdr = CMSG_FIRSTHDR(&msghdr); | ||||
ATF_REQUIRE_MSG(cmsghdr != NULL, | ATF_REQUIRE_MSG(cmsghdr != NULL, | ||||
"recvmsg: did not receive control message"); | "recvmsg: did not receive control message"); | ||||
foundcreds = false; | |||||
*recv_fd = -1; | *recv_fd = -1; | ||||
for (; cmsghdr != NULL; cmsghdr = CMSG_NXTHDR(&msghdr, cmsghdr)) { | for (; cmsghdr != NULL; cmsghdr = CMSG_NXTHDR(&msghdr, cmsghdr)) { | ||||
if (cmsghdr->cmsg_level == SOL_SOCKET && | if (cmsghdr->cmsg_level == SOL_SOCKET && | ||||
cmsghdr->cmsg_type == SCM_RIGHTS && | cmsghdr->cmsg_type == SCM_RIGHTS && | ||||
cmsghdr->cmsg_len == CMSG_LEN(sizeof(int))) { | cmsghdr->cmsg_len == CMSG_LEN(sizeof(int))) { | ||||
memcpy(recv_fd, CMSG_DATA(cmsghdr), sizeof(int)); | memcpy(recv_fd, CMSG_DATA(cmsghdr), sizeof(int)); | ||||
ATF_REQUIRE(*recv_fd != -1); | ATF_REQUIRE(*recv_fd != -1); | ||||
} else if (cmsghdr->cmsg_level == SOL_SOCKET && | |||||
cmsghdr->cmsg_type == SCM_CREDS) | |||||
foundcreds = true; | |||||
} | } | ||||
} | |||||
ATF_REQUIRE_MSG(*recv_fd != -1, | ATF_REQUIRE_MSG(*recv_fd != -1, | ||||
"recvmsg: did not receive single-fd message"); | "recvmsg: did not receive single-fd message"); | ||||
ATF_REQUIRE_MSG(!localcreds(sockfd) || foundcreds, | |||||
"recvmsg: expected credentials were not received"); | |||||
} | } | ||||
static void | static void | ||||
recvfd(int sockfd, int *recv_fd) | 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)); | ||||
▲ Show 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | ATF_TC_BODY(devfs_orphan, tc) | ||||
close(putfd); | close(putfd); | ||||
closesocketpair(fd); | closesocketpair(fd); | ||||
} | } | ||||
#define LOCAL_SENDSPACE_SYSCTL "net.local.stream.sendspace" | #define LOCAL_SENDSPACE_SYSCTL "net.local.stream.sendspace" | ||||
/* | /* | ||||
* Test for PR 181741. Receiver sets LOCAL_CREDS, and kernel prepends a | * Test for PR 181741. Receiver sets LOCAL_CREDS, and kernel prepends a | ||||
* control message to the data. Sender sends large payload. | * control message to the data. Sender sends large payload using a non-blocking | ||||
* Payload + SCM_RIGHTS + LOCAL_CREDS hit socket buffer limit, and receiver | * socket. Payload + SCM_RIGHTS + LOCAL_CREDS hit socket buffer limit, and | ||||
* receives truncated data. | * receiver receives truncated data. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(rights_creds_payload); | ATF_TC_WITHOUT_HEAD(rights_creds_payload); | ||||
ATF_TC_BODY(rights_creds_payload, tc) | ATF_TC_BODY(rights_creds_payload, tc) | ||||
{ | { | ||||
const int on = 1; | const int on = 1; | ||||
u_long sendspace; | u_long sendspace; | ||||
size_t len; | size_t len; | ||||
void *buf; | void *buf; | ||||
int fd[2], getfd, putfd, rc; | int fd[2], getfd, putfd, rc; | ||||
atf_tc_expect_fail("PR 181741: Packet loss when 'control' messages " | |||||
"are present with large data"); | |||||
len = sizeof(sendspace); | len = sizeof(sendspace); | ||||
rc = sysctlbyname(LOCAL_SENDSPACE_SYSCTL, &sendspace, | rc = sysctlbyname(LOCAL_SENDSPACE_SYSCTL, &sendspace, | ||||
&len, NULL, 0); | &len, NULL, 0); | ||||
ATF_REQUIRE_MSG(rc != -1, | ATF_REQUIRE_MSG(rc != -1, | ||||
"sysctl %s failed: %s", LOCAL_SENDSPACE_SYSCTL, strerror(errno)); | "sysctl %s failed: %s", LOCAL_SENDSPACE_SYSCTL, strerror(errno)); | ||||
buf = calloc(1, sendspace); | buf = calloc(1, sendspace); | ||||
ATF_REQUIRE(buf != NULL); | ATF_REQUIRE(buf != NULL); | ||||
domainsocketpair(fd); | domainsocketpair(fd); | ||||
tempfile(&putfd); | |||||
rc = fcntl(fd[0], F_SETFL, O_NONBLOCK); | |||||
ATF_REQUIRE_MSG(rc != -1, "fcntl(O_NONBLOCK) failed: %s", | |||||
strerror(errno)); | |||||
rc = setsockopt(fd[1], 0, LOCAL_CREDS, &on, sizeof(on)); | rc = setsockopt(fd[1], 0, LOCAL_CREDS, &on, sizeof(on)); | ||||
ATF_REQUIRE_MSG(rc != -1, "setsockopt(LOCAL_CREDS) failed: %s", | ATF_REQUIRE_MSG(rc != -1, "setsockopt(LOCAL_CREDS) failed: %s", | ||||
strerror(errno)); | strerror(errno)); | ||||
tempfile(&putfd); | |||||
sendfd_payload(fd[0], putfd, buf, sendspace); | len = sendfd_payload(fd[0], putfd, buf, sendspace); | ||||
recvfd_payload(fd[1], &getfd, buf, sendspace); | ATF_REQUIRE_MSG(len < sendspace, "sendmsg: %zu bytes sent", len); | ||||
recvfd_payload(fd[1], &getfd, buf, len); | |||||
close(putfd); | close(putfd); | ||||
close(getfd); | close(getfd); | ||||
closesocketpair(fd); | closesocketpair(fd); | ||||
} | } | ||||
/* | /* | ||||
* 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. | ||||
Show All 11 Lines | ATF_TC_BODY(truncated_rights, tc) | ||||
atf_tc_expect_fail("PR 131876: " | atf_tc_expect_fail("PR 131876: " | ||||
"FD leak when 'control' message is truncated"); | "FD leak when 'control' message is truncated"); | ||||
memset(buf, 42, sizeof(buf)); | memset(buf, 42, sizeof(buf)); | ||||
domainsocketpair(fd); | domainsocketpair(fd); | ||||
devnull(&putfd); | devnull(&putfd); | ||||
nfds = getnfds(); | nfds = getnfds(); | ||||
sendfd_payload(fd[0], putfd, buf, sizeof(buf)); | 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(&msghdr, sizeof(msghdr)); | ||||
bzero(message, sizeof(message)); | bzero(message, sizeof(message)); | ||||
iovec.iov_base = buf; | iovec.iov_base = buf; | ||||
iovec.iov_len = sizeof(buf); | iovec.iov_len = sizeof(buf); | ||||
msghdr.msg_control = message; | msghdr.msg_control = message; | ||||
msghdr.msg_controllen = sizeof(message); | msghdr.msg_controllen = sizeof(message); | ||||
▲ Show 20 Lines • Show All 75 Lines • Show Last 20 Lines |