Changeset View
Changeset View
Standalone View
Standalone View
tests/sys/kern/unix_passfd_test.c
Show First 20 Lines • Show All 188 Lines • ▼ Show 20 Lines | localcreds(int sockfd) | ||||
rc = getsockopt(sockfd, 0, LOCAL_CREDS, &val, &sz); | rc = getsockopt(sockfd, 0, LOCAL_CREDS, &val, &sz); | ||||
ATF_REQUIRE_MSG(rc != -1, "getsockopt(LOCAL_CREDS) failed: %s", | ATF_REQUIRE_MSG(rc != -1, "getsockopt(LOCAL_CREDS) failed: %s", | ||||
strerror(errno)); | strerror(errno)); | ||||
return (val != 0); | 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, | ||||
size_t cmsgsz) | size_t cmsgsz, int recvmsg_flags) | ||||
{ | { | ||||
struct cmsghdr *cmsghdr; | struct cmsghdr *cmsghdr; | ||||
struct msghdr msghdr; | struct msghdr msghdr; | ||||
struct iovec iovec; | struct iovec iovec; | ||||
char *message; | char *message; | ||||
ssize_t len; | ssize_t len; | ||||
bool foundcreds; | bool foundcreds; | ||||
bzero(&msghdr, sizeof(msghdr)); | bzero(&msghdr, sizeof(msghdr)); | ||||
message = malloc(cmsgsz); | message = malloc(cmsgsz); | ||||
ATF_REQUIRE(message != NULL); | ATF_REQUIRE(message != NULL); | ||||
msghdr.msg_control = message; | msghdr.msg_control = message; | ||||
msghdr.msg_controllen = cmsgsz; | msghdr.msg_controllen = cmsgsz; | ||||
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, recvmsg_flags); | ||||
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; | foundcreds = false; | ||||
Show All 10 Lines | recvfd_payload(int sockfd, int *recv_fd, void *buf, size_t buflen, | ||||
} | } | ||||
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, | ATF_REQUIRE_MSG(!localcreds(sockfd) || foundcreds, | ||||
"recvmsg: expected credentials were not received"); | "recvmsg: expected credentials were not received"); | ||||
} | } | ||||
static void | static void | ||||
recvfd(int sockfd, int *recv_fd) | recvfd(int sockfd, int *recv_fd, int flags) | ||||
{ | { | ||||
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))); | CMSG_SPACE(sizeof(int)), flags); | ||||
} | } | ||||
/* | /* | ||||
* Put a temporary file into a UNIX domain socket, then take it out and make | * 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 | * sure it's the same file. First time around, don't close the reference | ||||
* after sending. | * after sending. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(simple_send_fd); | ATF_TC_WITHOUT_HEAD(simple_send_fd); | ||||
ATF_TC_BODY(simple_send_fd, tc) | ATF_TC_BODY(simple_send_fd, tc) | ||||
{ | { | ||||
struct stat getfd_stat, putfd_stat; | struct stat getfd_stat, putfd_stat; | ||||
int fd[2], getfd, putfd; | int fd[2], getfd, putfd; | ||||
domainsocketpair(fd); | domainsocketpair(fd); | ||||
tempfile(&putfd); | tempfile(&putfd); | ||||
dofstat(putfd, &putfd_stat); | dofstat(putfd, &putfd_stat); | ||||
sendfd(fd[0], putfd); | sendfd(fd[0], putfd); | ||||
recvfd(fd[1], &getfd); | recvfd(fd[1], &getfd, 0); | ||||
dofstat(getfd, &getfd_stat); | dofstat(getfd, &getfd_stat); | ||||
samefile(&putfd_stat, &getfd_stat); | samefile(&putfd_stat, &getfd_stat); | ||||
close(putfd); | close(putfd); | ||||
close(getfd); | close(getfd); | ||||
closesocketpair(fd); | closesocketpair(fd); | ||||
} | } | ||||
/* | /* | ||||
* Like simple_send_fd but also sets MSG_CMSG_CLOEXEC and checks that the | |||||
* received file descriptor has the FD_CLOEXEC flag set. | |||||
*/ | |||||
ATF_TC_WITHOUT_HEAD(simple_send_fd_msg_cmsg_cloexec); | |||||
ATF_TC_BODY(simple_send_fd_msg_cmsg_cloexec, tc) | |||||
{ | |||||
struct stat getfd_stat, putfd_stat; | |||||
int fd[2], getfd, putfd; | |||||
domainsocketpair(fd); | |||||
tempfile(&putfd); | |||||
dofstat(putfd, &putfd_stat); | |||||
sendfd(fd[0], putfd); | |||||
recvfd(fd[1], &getfd, MSG_CMSG_CLOEXEC); | |||||
dofstat(getfd, &getfd_stat); | |||||
samefile(&putfd_stat, &getfd_stat); | |||||
ATF_REQUIRE_EQ_MSG(fcntl(getfd, F_GETFD) & FD_CLOEXEC, FD_CLOEXEC, | |||||
"FD_CLOEXEC not set on the received file descriptor"); | |||||
close(putfd); | |||||
close(getfd); | |||||
closesocketpair(fd); | |||||
} | |||||
/* | |||||
* Same as simple_send_fd, only close the file reference after sending, so that | * Same as simple_send_fd, only close the file reference after sending, so that | ||||
* the only reference is the descriptor in the UNIX domain socket buffer. | * the only reference is the descriptor in the UNIX domain socket buffer. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(send_and_close); | ATF_TC_WITHOUT_HEAD(send_and_close); | ||||
ATF_TC_BODY(send_and_close, tc) | ATF_TC_BODY(send_and_close, tc) | ||||
{ | { | ||||
struct stat getfd_stat, putfd_stat; | struct stat getfd_stat, putfd_stat; | ||||
int fd[2], getfd, putfd; | int fd[2], getfd, putfd; | ||||
domainsocketpair(fd); | domainsocketpair(fd); | ||||
tempfile(&putfd); | tempfile(&putfd); | ||||
dofstat(putfd, &putfd_stat); | dofstat(putfd, &putfd_stat); | ||||
sendfd(fd[0], putfd); | sendfd(fd[0], putfd); | ||||
close(putfd); | close(putfd); | ||||
recvfd(fd[1], &getfd); | recvfd(fd[1], &getfd, 0); | ||||
dofstat(getfd, &getfd_stat); | dofstat(getfd, &getfd_stat); | ||||
samefile(&putfd_stat, &getfd_stat); | samefile(&putfd_stat, &getfd_stat); | ||||
close(getfd); | close(getfd); | ||||
closesocketpair(fd); | closesocketpair(fd); | ||||
} | } | ||||
/* | /* | ||||
* Put a temporary file into a UNIX domain socket, then close both endpoints | * Put a temporary file into a UNIX domain socket, then close both endpoints | ||||
Show All 25 Lines | ATF_TC_BODY(two_files, tc) | ||||
tempfile(&putfd_1); | tempfile(&putfd_1); | ||||
tempfile(&putfd_2); | tempfile(&putfd_2); | ||||
dofstat(putfd_1, &putfd_1_stat); | dofstat(putfd_1, &putfd_1_stat); | ||||
dofstat(putfd_2, &putfd_2_stat); | dofstat(putfd_2, &putfd_2_stat); | ||||
sendfd(fd[0], putfd_1); | sendfd(fd[0], putfd_1); | ||||
sendfd(fd[0], putfd_2); | sendfd(fd[0], putfd_2); | ||||
close(putfd_1); | close(putfd_1); | ||||
close(putfd_2); | close(putfd_2); | ||||
recvfd(fd[1], &getfd_1); | recvfd(fd[1], &getfd_1, 0); | ||||
recvfd(fd[1], &getfd_2); | recvfd(fd[1], &getfd_2, 0); | ||||
dofstat(getfd_1, &getfd_1_stat); | dofstat(getfd_1, &getfd_1_stat); | ||||
dofstat(getfd_2, &getfd_2_stat); | dofstat(getfd_2, &getfd_2_stat); | ||||
samefile(&putfd_1_stat, &getfd_1_stat); | samefile(&putfd_1_stat, &getfd_1_stat); | ||||
samefile(&putfd_2_stat, &getfd_2_stat); | samefile(&putfd_2_stat, &getfd_2_stat); | ||||
close(getfd_1); | close(getfd_1); | ||||
close(getfd_2); | close(getfd_2); | ||||
closesocketpair(fd); | closesocketpair(fd); | ||||
} | } | ||||
/* | /* | ||||
* Big bundling test. Send an endpoint of the UNIX domain socket over itself, | * Big bundling test. Send an endpoint of the UNIX domain socket over itself, | ||||
* closing the door behind it. | * closing the door behind it. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(bundle); | ATF_TC_WITHOUT_HEAD(bundle); | ||||
ATF_TC_BODY(bundle, tc) | ATF_TC_BODY(bundle, tc) | ||||
{ | { | ||||
int fd[2], getfd; | int fd[2], getfd; | ||||
domainsocketpair(fd); | domainsocketpair(fd); | ||||
sendfd(fd[0], fd[0]); | sendfd(fd[0], fd[0]); | ||||
close(fd[0]); | close(fd[0]); | ||||
recvfd(fd[1], &getfd); | recvfd(fd[1], &getfd, 0); | ||||
close(getfd); | close(getfd); | ||||
close(fd[1]); | close(fd[1]); | ||||
} | } | ||||
/* | /* | ||||
* Big bundling test part two: Send an endpoint of the UNIX domain socket over | * Big bundling test part two: Send an endpoint of the UNIX domain socket over | ||||
* itself, close the door behind it, and never remove it from the other end. | * itself, close the door behind it, and never remove it from the other end. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | ATF_REQUIRE_MSG(rc != -1, "fcntl(O_NONBLOCK) failed: %s", | ||||
strerror(errno)); | 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)); | ||||
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))); | CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + CMSG_SPACE(sizeof(int)), 0); | ||||
close(putfd); | close(putfd); | ||||
close(getfd); | close(getfd); | ||||
closesocketpair(fd); | closesocketpair(fd); | ||||
} | } | ||||
static void | static void | ||||
send_cmsg(int sockfd, void *cmsg, size_t cmsgsz) | send_cmsg(int sockfd, void *cmsg, size_t cmsgsz) | ||||
▲ Show 20 Lines • Show All 248 Lines • ▼ Show 20 Lines | ATF_TC_BODY(empty_rights_message, tc) | ||||
(void)close(putfd); | (void)close(putfd); | ||||
} | } | ||||
ATF_TP_ADD_TCS(tp) | ATF_TP_ADD_TCS(tp) | ||||
{ | { | ||||
ATF_TP_ADD_TC(tp, simple_send_fd); | ATF_TP_ADD_TC(tp, simple_send_fd); | ||||
ATF_TP_ADD_TC(tp, simple_send_fd_msg_cmsg_cloexec); | |||||
ATF_TP_ADD_TC(tp, send_and_close); | ATF_TP_ADD_TC(tp, send_and_close); | ||||
ATF_TP_ADD_TC(tp, send_and_cancel); | ATF_TP_ADD_TC(tp, send_and_cancel); | ||||
ATF_TP_ADD_TC(tp, two_files); | ATF_TP_ADD_TC(tp, two_files); | ||||
ATF_TP_ADD_TC(tp, bundle); | ATF_TP_ADD_TC(tp, bundle); | ||||
ATF_TP_ADD_TC(tp, bundle_cancel); | ATF_TP_ADD_TC(tp, bundle_cancel); | ||||
ATF_TP_ADD_TC(tp, devfs_orphan); | ATF_TP_ADD_TC(tp, devfs_orphan); | ||||
ATF_TP_ADD_TC(tp, rights_creds_payload); | ATF_TP_ADD_TC(tp, rights_creds_payload); | ||||
ATF_TP_ADD_TC(tp, truncated_rights); | ATF_TP_ADD_TC(tp, truncated_rights); | ||||
ATF_TP_ADD_TC(tp, copyout_rights_error); | ATF_TP_ADD_TC(tp, copyout_rights_error); | ||||
ATF_TP_ADD_TC(tp, empty_rights_message); | ATF_TP_ADD_TC(tp, empty_rights_message); | ||||
return (atf_no_error()); | return (atf_no_error()); | ||||
} | } |