From de6ff3e54861039cd1644d4df1631c987f250a6a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 5 Feb 2021 19:36:26 +0100 Subject: [PATCH 1/8] swrap: fix invalid read in swrap_sendmsg_unix_scm_rights() Here the fds_out array is larger than the fds_in array, so we can only copy the fds_in array using size_fds_in, leaving the last slot of fds_out untouched, which is filled by fds_out[num_fds_in] = pipefd[0] later. Signed-off-by: Stefan Metzmacher --- src/socket_wrapper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index 43a5892..e8c2d6c 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -5450,7 +5450,7 @@ static int swrap_sendmsg_unix_scm_rights(const struct cmsghdr *cmsg, *new_cmsg = *cmsg; __fds_out.p = CMSG_DATA(new_cmsg); fds_out = __fds_out.fds; - memcpy(fds_out, fds_in, size_fds_out); + memcpy(fds_out, fds_in, size_fds_in); new_cmsg->cmsg_len = cmsg->cmsg_len; for (i = 0; i < num_fds_in; i++) { -- GitLab From b406a28a677eaf7395f956a52da0b8d13600f72b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 4 Feb 2021 16:20:13 +0100 Subject: [PATCH 2/8] swrap: fix fd-passing without 4 padding bytes We noticed the problem on 32 bit platforms and sending a single application fd, the hidden pipe-fd doesn't fit into the padding bytes. This can also happen on 64 bit platforms and an even number of application fds. Signed-off-by: Stefan Metzmacher --- src/socket_wrapper.c | 69 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index e8c2d6c..ece3493 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -5962,8 +5962,48 @@ static ssize_t swrap_sendmsg_after_unix(struct msghdr *msg_tmp, static int swrap_recvmsg_before_unix(struct msghdr *msg_in, struct msghdr *msg_tmp) { +#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL + const size_t cm_extra_space = CMSG_SPACE(sizeof(int)); + uint8_t *cm_data = NULL; + size_t cm_data_space = 0; + *msg_tmp = *msg_in; + + SWRAP_LOG(SWRAP_LOG_TRACE, + "msg_in->msg_controllen=%zu", + (size_t)msg_in->msg_controllen); + + /* Nothing to do */ + if (msg_in->msg_controllen == 0 || msg_in->msg_control == NULL) { + return 0; + } + + /* + * We need to give the kernel a bit more space in order + * recv the pipe fd, added by swrap_sendmsg_before_unix()). + * swrap_recvmsg_after_unix() will hide it again. + */ + cm_data_space = msg_in->msg_controllen; + if (cm_data_space < (INT32_MAX - cm_extra_space)) { + cm_data_space += cm_extra_space; + } + cm_data = calloc(1, cm_data_space); + if (cm_data == NULL) { + return -1; + } + memcpy(cm_data, msg_in->msg_control, msg_in->msg_controllen); + + msg_tmp->msg_controllen = cm_data_space; + msg_tmp->msg_control = cm_data; + + SWRAP_LOG(SWRAP_LOG_TRACE, + "msg_tmp->msg_controllen=%zu", + (size_t)msg_tmp->msg_controllen); return 0; +#else /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ + *msg_tmp = *msg_in; + return 0; +#endif /* ! HAVE_STRUCT_MSGHDR_MSG_CONTROL */ } static ssize_t swrap_recvmsg_after_unix(struct msghdr *msg_tmp, @@ -5976,9 +6016,14 @@ static ssize_t swrap_recvmsg_after_unix(struct msghdr *msg_tmp, size_t cm_data_space = 0; int rc = -1; + SWRAP_LOG(SWRAP_LOG_TRACE, + "msg_tmp->msg_controllen=%zu", + (size_t)msg_tmp->msg_controllen); + /* Nothing to do */ if (msg_tmp->msg_controllen == 0 || msg_tmp->msg_control == NULL) { - goto done; + *msg_out = *msg_tmp; + return ret; } for (cmsg = CMSG_FIRSTHDR(msg_tmp); @@ -6006,15 +6051,27 @@ static ssize_t swrap_recvmsg_after_unix(struct msghdr *msg_tmp, } /* - * msg_tmp->msg_control is still the buffer of the caller. + * msg_tmp->msg_control was created by swrap_recvmsg_before_unix() + * and msg_out->msg_control is still the buffer of the caller. */ - memcpy(msg_tmp->msg_control, cm_data, cm_data_space); - msg_tmp->msg_controllen = cm_data_space; + SAFE_FREE(msg_tmp->msg_control); + msg_tmp->msg_control = msg_out->msg_control; + msg_tmp->msg_controllen = msg_out->msg_controllen; + *msg_out = *msg_tmp; + + cm_data_space = MIN(cm_data_space, msg_out->msg_controllen); + memcpy(msg_out->msg_control, cm_data, cm_data_space); + msg_out->msg_controllen = cm_data_space; SAFE_FREE(cm_data); -done: -#endif /* ! HAVE_STRUCT_MSGHDR_MSG_CONTROL */ + + SWRAP_LOG(SWRAP_LOG_TRACE, + "msg_out->msg_controllen=%zu", + (size_t)msg_out->msg_controllen); + return ret; +#else /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ *msg_out = *msg_tmp; return ret; +#endif /* ! HAVE_STRUCT_MSGHDR_MSG_CONTROL */ } static ssize_t swrap_sendmsg_before(int fd, -- GitLab From b30872b5950a73dfe34abd687867ae4c88652dcf Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 5 Feb 2021 15:41:27 +0100 Subject: [PATCH 3/8] tests/echo_srv: allow more than once tcp connection at a time We should not wait for the last connection to disconnect, there would not be any reason to use fork at all. Signed-off-by: Stefan Metzmacher --- tests/echo_srv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/echo_srv.c b/tests/echo_srv.c index 0aefa9a..fbb6637 100644 --- a/tests/echo_srv.c +++ b/tests/echo_srv.c @@ -537,6 +537,7 @@ static void echo_tcp(int sock) pid_t pid; while (1) { + waitpid(-1, NULL, WNOHANG); s = accept(sock, &addr.sa.s, &addr.sa_socklen); if (s == -1 && errno == ECONNABORTED) { continue; @@ -575,7 +576,6 @@ static void echo_tcp(int sock) close(s); exit(0); } - waitpid(-1, NULL, 0); close(s); } -- GitLab From e20433d25f692b5f56588de08d66988faa536db8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 4 Feb 2021 17:04:30 +0100 Subject: [PATCH 4/8] test_echo_tcp_sendmsg_recvmsg_fd: split out test_tcp_sendmsg_recvmsg_fd_array() This will allow us to test more combinations in order to get better coverage. For now we just test a single fd. Signed-off-by: Stefan Metzmacher --- tests/test_echo_tcp_sendmsg_recvmsg_fd.c | 198 +++++++++++++++++------ 1 file changed, 145 insertions(+), 53 deletions(-) diff --git a/tests/test_echo_tcp_sendmsg_recvmsg_fd.c b/tests/test_echo_tcp_sendmsg_recvmsg_fd.c index 8ae1a60..b0156c9 100644 --- a/tests/test_echo_tcp_sendmsg_recvmsg_fd.c +++ b/tests/test_echo_tcp_sendmsg_recvmsg_fd.c @@ -33,33 +33,86 @@ static int teardown(void **state) return 0; } -static void test_tcp_sendmsg_recvmsg_fd(void **state) +struct test_fd { + int fd; + struct torture_address sock_addr; + struct torture_address peer_addr; +}; + +static int test_fill_test_fd(struct test_fd *tfd, int fd) { - struct torture_address addr = { - .sa_socklen = sizeof(struct sockaddr_in), + struct torture_address saddr = { + .sa_socklen = sizeof(struct sockaddr_storage), }; - int pass_sock_fd; - int sv[2]; - int child_fd, parent_fd; - pid_t pid; - int rc; + struct torture_address paddr = { + .sa_socklen = sizeof(struct sockaddr_storage), + }; + int ret; - (void) state; /* unused */ + *tfd = (struct test_fd) { .fd = fd, }; - /* create socket file descriptor to be passed */ - pass_sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - assert_int_not_equal(pass_sock_fd, -1); + ret = getsockname(fd, &saddr.sa.s, &saddr.sa_socklen); + if (ret == -1 && errno == ENOTSOCK) { + return 0; + } + if (ret == -1) { + return ret; + } - addr.sa.in.sin_family = AF_INET; - addr.sa.in.sin_port = htons(torture_server_port()); + ret = getpeername(fd, &paddr.sa.s, &paddr.sa_socklen); + if (ret == -1) { + return ret; + } - rc = inet_pton(addr.sa.in.sin_family, - torture_server_address(AF_INET), - &addr.sa.in.sin_addr); - assert_int_equal(rc, 1); + tfd->sock_addr = saddr; + tfd->peer_addr = paddr; + return 0; +} - rc = connect(pass_sock_fd, &addr.sa.s, addr.sa_socklen); - assert_int_equal(rc, 0); +static void _assert_torture_address_equal(const struct torture_address *ga, + const struct torture_address *ea, + const char * const file, + const int line) +{ + _assert_int_equal(ga->sa_socklen, ea->sa_socklen, file, line); + if (ga->sa_socklen == 0) { + return; + } + _assert_memory_equal(&ga->sa, &ea->sa, ga->sa_socklen, file, line); +} + +#define assert_test_fd_equal(gfd, efd) \ + _assert_test_fd_equal(gfd, efd, __FILE__, __LINE__) + +static void _assert_test_fd_equal(const struct test_fd *gfd, + const struct test_fd *efd, + const char * const file, + const int line) +{ + if (efd->fd == -1) { + _assert_int_equal(gfd->fd, -1, file, line); + return; + } + + _assert_int_not_equal(gfd->fd, -1, file, line); + + _assert_torture_address_equal(&gfd->sock_addr, &efd->sock_addr, file, line); + _assert_torture_address_equal(&gfd->peer_addr, &efd->peer_addr, file, line); +} + +static void test_tcp_sendmsg_recvmsg_fd_array(const int *fds, size_t num_fds) +{ + struct test_fd tfds[num_fds]; + size_t idx; + int sv[2]; + int child_fd, parent_fd; + pid_t pid; + int rc; + + for (idx = 0; idx < num_fds; idx++) { + rc = test_fill_test_fd(&tfds[idx], fds[idx]); + assert_int_equal(rc, 0); + } /* create unix domain socket stream */ rc = socketpair(AF_LOCAL, SOCK_STREAM, 0, sv); @@ -73,17 +126,11 @@ static void test_tcp_sendmsg_recvmsg_fd(void **state) if (pid == 0) { /* Child */ - struct torture_address peer_addr = { - .sa_socklen = sizeof(struct sockaddr_in), - }; struct msghdr child_msg; - char cmsgbuf[CMSG_SPACE(sizeof(int))]; + int recv_fd_array[num_fds]; + char cmsgbuf[CMSG_SPACE(sizeof(int)*num_fds)]; struct cmsghdr *cmsg; - int rcv_sock_fd, port; ssize_t ret; - char send_buf[64] = {0}; - char recv_buf[64] = {0}; - char ipstr[INET_ADDRSTRLEN]; char byte = { 0, }; struct iovec iov; @@ -104,45 +151,62 @@ static void test_tcp_sendmsg_recvmsg_fd(void **state) assert_non_null(cmsg); assert_int_equal(cmsg->cmsg_type, SCM_RIGHTS); - memcpy(&rcv_sock_fd, CMSG_DATA(cmsg), sizeof(rcv_sock_fd)); - assert_int_not_equal(rcv_sock_fd, -1); + memcpy(recv_fd_array, CMSG_DATA(cmsg), sizeof(int)*num_fds); + for (idx = 0; idx < num_fds; idx++) { + assert_int_not_equal(recv_fd_array[idx], -1); + } - /* extract peer info from received socket fd */ - ret = getpeername(rcv_sock_fd, &peer_addr.sa.s, &peer_addr.sa_socklen); - assert_int_not_equal(ret, -1); + for (idx = 0; idx < num_fds; idx++) { + struct test_fd recv_tfd = { .fd = -1, }; - port = ntohs(peer_addr.sa.in.sin_port); - inet_ntop(AF_INET, &peer_addr.sa.in.sin_addr, ipstr, sizeof(ipstr)); + ret = test_fill_test_fd(&recv_tfd, recv_fd_array[idx]); + assert_int_equal(ret, 0); - /* check whether it is the same socket previously connected */ - assert_string_equal(ipstr, torture_server_address(AF_INET)); - assert_int_equal(port, torture_server_port()); + assert_test_fd_equal(&recv_tfd, &tfds[idx]); + } - snprintf(send_buf, sizeof(send_buf), "packet"); + for (idx = 0; idx < num_fds; idx++) { + int recv_fd = recv_fd_array[idx]; + char send_buf[64] = {0,}; + char recv_buf[64] = {0,}; - ret = write(rcv_sock_fd, - send_buf, - sizeof(send_buf)); - assert_int_not_equal(ret, -1); + if (tfds[idx].sock_addr.sa_socklen == 0) { + /* + * skip fds not belonging to + * a socket. + */ + continue; + } - ret = read(rcv_sock_fd, - recv_buf, - sizeof(recv_buf)); - assert_int_not_equal(ret, -1); + snprintf(send_buf, sizeof(send_buf), "packet"); - assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); + ret = write(recv_fd, + send_buf, + sizeof(send_buf)); + assert_int_not_equal(ret, -1); + + ret = read(recv_fd, + recv_buf, + sizeof(recv_buf)); + assert_int_not_equal(ret, -1); + + assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); + } exit(0); } else { /* Parent */ struct msghdr parent_msg; struct cmsghdr *cmsg; - char cmsgbuf[CMSG_SPACE(sizeof(pass_sock_fd))]; + char cmsgbuf[CMSG_SPACE(sizeof(int)*num_fds)]; + int pass_fd_array[num_fds]; char byte = '!'; struct iovec iov; int cs; - (void) state; /* unused */ + for (idx = 0; idx < num_fds; idx++) { + pass_fd_array[idx] = tfds[idx].fd; + } iov.iov_base = &byte; iov.iov_len = 1; @@ -156,10 +220,10 @@ static void test_tcp_sendmsg_recvmsg_fd(void **state) cmsg = CMSG_FIRSTHDR(&parent_msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(pass_sock_fd)); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)*num_fds); /* place previously connected socket fd as ancillary data */ - memcpy(CMSG_DATA(cmsg), &pass_sock_fd, sizeof(pass_sock_fd)); + memcpy(CMSG_DATA(cmsg), pass_fd_array, sizeof(int)*num_fds); parent_msg.msg_controllen = cmsg->cmsg_len; rc = sendmsg(parent_fd, &parent_msg, 0); @@ -173,11 +237,39 @@ static void test_tcp_sendmsg_recvmsg_fd(void **state) } } +static void test_tcp_sendmsg_recvmsg_fd_1(void **state) +{ + struct torture_address addr = { + .sa_socklen = sizeof(struct sockaddr_in), + }; + int pass_sock_fd; + int rc; + + (void) state; /* unused */ + + /* create socket file descriptor to be passed */ + pass_sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + assert_int_not_equal(pass_sock_fd, -1); + + addr.sa.in.sin_family = AF_INET; + addr.sa.in.sin_port = htons(torture_server_port()); + + rc = inet_pton(addr.sa.in.sin_family, + torture_server_address(AF_INET), + &addr.sa.in.sin_addr); + assert_int_equal(rc, 1); + + rc = connect(pass_sock_fd, &addr.sa.s, addr.sa_socklen); + assert_int_equal(rc, 0); + + test_tcp_sendmsg_recvmsg_fd_array(&pass_sock_fd, 1); +} + int main(void) { int rc; const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd, + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_1, setup_echo_srv_tcp_ipv4, teardown) }; -- GitLab From 0802e3660a3df29a76cbfe4f2ab4f37f92bd26ac Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 5 Feb 2021 14:10:03 +0100 Subject: [PATCH 5/8] test_echo_tcp_sendmsg_recvmsg_fd: split out test_tcp_sendmsg_recvmsg_fd_same() Signed-off-by: Stefan Metzmacher --- tests/test_echo_tcp_sendmsg_recvmsg_fd.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/test_echo_tcp_sendmsg_recvmsg_fd.c b/tests/test_echo_tcp_sendmsg_recvmsg_fd.c index b0156c9..e1908ae 100644 --- a/tests/test_echo_tcp_sendmsg_recvmsg_fd.c +++ b/tests/test_echo_tcp_sendmsg_recvmsg_fd.c @@ -237,16 +237,16 @@ static void test_tcp_sendmsg_recvmsg_fd_array(const int *fds, size_t num_fds) } } -static void test_tcp_sendmsg_recvmsg_fd_1(void **state) +static void test_tcp_sendmsg_recvmsg_fd_same(size_t num_fds) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; int pass_sock_fd; + int fd_array[num_fds]; + size_t idx; int rc; - (void) state; /* unused */ - /* create socket file descriptor to be passed */ pass_sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(pass_sock_fd, -1); @@ -262,7 +262,19 @@ static void test_tcp_sendmsg_recvmsg_fd_1(void **state) rc = connect(pass_sock_fd, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); - test_tcp_sendmsg_recvmsg_fd_array(&pass_sock_fd, 1); + for (idx = 0; idx < num_fds; idx++) { + fd_array[idx] = pass_sock_fd; + } + + test_tcp_sendmsg_recvmsg_fd_array(fd_array, num_fds); + + close(pass_sock_fd); +} + +static void test_tcp_sendmsg_recvmsg_fd_1(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_same(1); } int main(void) { -- GitLab From 23bab2ac4f9a1dbdd69c2107abe57a374b606435 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 5 Feb 2021 14:20:16 +0100 Subject: [PATCH 6/8] test_echo_tcp_sendmsg_recvmsg_fd: also test passing the same socket up to 6 times Note SWRAP_MAX_PASSED_FDS is currently 6. This test demonstrates that even 64-bit systems required commit: "swrap: fix fd-passing without 4 padding bytes" Signed-off-by: Stefan Metzmacher --- tests/test_echo_tcp_sendmsg_recvmsg_fd.c | 47 +++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/tests/test_echo_tcp_sendmsg_recvmsg_fd.c b/tests/test_echo_tcp_sendmsg_recvmsg_fd.c index e1908ae..9f0ac85 100644 --- a/tests/test_echo_tcp_sendmsg_recvmsg_fd.c +++ b/tests/test_echo_tcp_sendmsg_recvmsg_fd.c @@ -277,13 +277,58 @@ static void test_tcp_sendmsg_recvmsg_fd_1(void **state) test_tcp_sendmsg_recvmsg_fd_same(1); } +static void test_tcp_sendmsg_recvmsg_fd_2s(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_same(2); +} + +static void test_tcp_sendmsg_recvmsg_fd_3s(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_same(3); +} + +static void test_tcp_sendmsg_recvmsg_fd_4s(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_same(4); +} + +static void test_tcp_sendmsg_recvmsg_fd_5s(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_same(5); +} + +static void test_tcp_sendmsg_recvmsg_fd_6s(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_same(6); +} + int main(void) { int rc; const struct CMUnitTest tests[] = { cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_1, setup_echo_srv_tcp_ipv4, - teardown) + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_2s, + setup_echo_srv_tcp_ipv4, + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_3s, + setup_echo_srv_tcp_ipv4, + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_4s, + setup_echo_srv_tcp_ipv4, + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_5s, + setup_echo_srv_tcp_ipv4, + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_6s, + setup_echo_srv_tcp_ipv4, + teardown), }; rc = cmocka_run_group_tests(tests, NULL, NULL); -- GitLab From 83ba2f63a286e77dce4c4e991363e128cb90c725 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 5 Feb 2021 14:40:45 +0100 Subject: [PATCH 7/8] test_echo_tcp_sendmsg_recvmsg_fd: add test_tcp_sendmsg_recvmsg_fd_different() tests Signed-off-by: Stefan Metzmacher --- tests/test_echo_tcp_sendmsg_recvmsg_fd.c | 82 ++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/tests/test_echo_tcp_sendmsg_recvmsg_fd.c b/tests/test_echo_tcp_sendmsg_recvmsg_fd.c index 9f0ac85..f683892 100644 --- a/tests/test_echo_tcp_sendmsg_recvmsg_fd.c +++ b/tests/test_echo_tcp_sendmsg_recvmsg_fd.c @@ -307,6 +307,73 @@ static void test_tcp_sendmsg_recvmsg_fd_6s(void **state) test_tcp_sendmsg_recvmsg_fd_same(6); } +static void test_tcp_sendmsg_recvmsg_fd_different(size_t num_fds) +{ + int fd_array[num_fds]; + size_t idx; + + for (idx = 0; idx < num_fds; idx++) { + struct torture_address addr = { + .sa_socklen = sizeof(struct sockaddr_in), + }; + int pass_sock_fd; + int rc; + + /* create socket file descriptor to be passed */ + pass_sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + assert_int_not_equal(pass_sock_fd, -1); + + addr.sa.in.sin_family = AF_INET; + addr.sa.in.sin_port = htons(torture_server_port()); + + rc = inet_pton(addr.sa.in.sin_family, + torture_server_address(AF_INET), + &addr.sa.in.sin_addr); + assert_int_equal(rc, 1); + + rc = connect(pass_sock_fd, &addr.sa.s, addr.sa_socklen); + assert_int_equal(rc, 0); + + fd_array[idx] = pass_sock_fd; + } + + test_tcp_sendmsg_recvmsg_fd_array(fd_array, num_fds); + + for (idx = 0; idx < num_fds; idx++) { + close(fd_array[idx]); + } +} + +static void test_tcp_sendmsg_recvmsg_fd_2d(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_different(2); +} + +static void test_tcp_sendmsg_recvmsg_fd_3d(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_different(3); +} + +static void test_tcp_sendmsg_recvmsg_fd_4d(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_different(4); +} + +static void test_tcp_sendmsg_recvmsg_fd_5d(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_different(5); +} + +static void test_tcp_sendmsg_recvmsg_fd_6d(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_different(6); +} + int main(void) { int rc; @@ -329,6 +396,21 @@ int main(void) { cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_6s, setup_echo_srv_tcp_ipv4, teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_2d, + setup_echo_srv_tcp_ipv4, + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_3d, + setup_echo_srv_tcp_ipv4, + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_4d, + setup_echo_srv_tcp_ipv4, + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_5d, + setup_echo_srv_tcp_ipv4, + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_6d, + setup_echo_srv_tcp_ipv4, + teardown), }; rc = cmocka_run_group_tests(tests, NULL, NULL); -- GitLab From 9aece7520f84e4b8e1c4e78097acfd5869c66d41 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 5 Feb 2021 16:25:43 +0100 Subject: [PATCH 8/8] test_echo_tcp_sendmsg_recvmsg_fd: add test_tcp_sendmsg_recvmsg_fd_mixed() tests Here we mix sockets and other valid file descriptors. Signed-off-by: Stefan Metzmacher --- tests/test_echo_tcp_sendmsg_recvmsg_fd.c | 165 +++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/tests/test_echo_tcp_sendmsg_recvmsg_fd.c b/tests/test_echo_tcp_sendmsg_recvmsg_fd.c index f683892..215d5ff 100644 --- a/tests/test_echo_tcp_sendmsg_recvmsg_fd.c +++ b/tests/test_echo_tcp_sendmsg_recvmsg_fd.c @@ -178,6 +178,14 @@ static void test_tcp_sendmsg_recvmsg_fd_array(const int *fds, size_t num_fds) continue; } + if (tfds[idx].sock_addr.sa.s.sa_family == AF_UNIX) { + /* + * skip fds not belonging to + * a socket. + */ + continue; + } + snprintf(send_buf, sizeof(send_buf), "packet"); ret = write(recv_fd, @@ -374,6 +382,145 @@ static void test_tcp_sendmsg_recvmsg_fd_6d(void **state) test_tcp_sendmsg_recvmsg_fd_different(6); } +static void test_tcp_sendmsg_recvmsg_fd_mixed(size_t num_fds) +{ + int fd_array[num_fds]; + int close_array[num_fds]; + size_t idx; + + for (idx = 0; idx < num_fds; idx++) { + fd_array[idx] = -1; + close_array[idx] = -1; + } + + /* + * We send + * 0: AF_UNIX + * 1: TCP + * 2: /dev/null + * 3: pipe + * 4: AF_UNIX + * 5: TCP + * 6: /dev/null + * 7: pipe + * . + * . + * . + * + */ + + for (idx = 0; idx < num_fds; idx++) { + int sv[2]; + int rc; + + if ((idx % 4) == 0) { + rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + assert_int_not_equal(rc, -1); + } else if ((idx % 4) == 2) { + rc = pipe(sv); + assert_int_not_equal(rc, -1); + } else { + continue; + } + + fd_array[idx] = sv[0]; + close_array[idx] = sv[1]; + } + + for (idx = 0; idx < num_fds; idx++) { + struct torture_address addr = { + .sa_socklen = sizeof(struct sockaddr_in), + }; + int pass_sock_fd; + int rc; + + if ((idx % 4) != 1) { + continue; + } + + /* create socket file descriptor to be passed */ + pass_sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + assert_int_not_equal(pass_sock_fd, -1); + + addr.sa.in.sin_family = AF_INET; + addr.sa.in.sin_port = htons(torture_server_port()); + + rc = inet_pton(addr.sa.in.sin_family, + torture_server_address(AF_INET), + &addr.sa.in.sin_addr); + assert_int_equal(rc, 1); + + rc = connect(pass_sock_fd, &addr.sa.s, addr.sa_socklen); + assert_int_equal(rc, 0); + + fd_array[idx] = pass_sock_fd; + } + + for (idx = 0; idx < num_fds; idx++) { + int pass_fd; + + if ((idx % 4) != 3) { + continue; + } + + /* create socket file descriptor to be passed */ + pass_fd = open("/dev/null", O_RDWR); + assert_int_not_equal(pass_fd, -1); + + fd_array[idx] = pass_fd; + } + + for (idx = 0; idx < num_fds; idx++) { + assert_int_not_equal(fd_array[idx], -1); + } + + test_tcp_sendmsg_recvmsg_fd_array(fd_array, num_fds); + + for (idx = 0; idx < num_fds; idx++) { + close(fd_array[idx]); + if (close_array[idx] == -1) { + continue; + } + close(close_array[idx]); + } +} + +static void test_tcp_sendmsg_recvmsg_fd_1m(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_mixed(1); +} + +static void test_tcp_sendmsg_recvmsg_fd_2m(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_mixed(2); +} + +static void test_tcp_sendmsg_recvmsg_fd_3m(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_mixed(3); +} + +static void test_tcp_sendmsg_recvmsg_fd_4m(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_mixed(4); +} + +static void test_tcp_sendmsg_recvmsg_fd_5m(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_mixed(5); +} + +static void test_tcp_sendmsg_recvmsg_fd_6m(void **state) +{ + (void) state; /* unused */ + test_tcp_sendmsg_recvmsg_fd_mixed(6); +} + int main(void) { int rc; @@ -411,6 +558,24 @@ int main(void) { cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_6d, setup_echo_srv_tcp_ipv4, teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_1m, + setup_echo_srv_tcp_ipv4, + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_2m, + setup_echo_srv_tcp_ipv4, + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_3m, + setup_echo_srv_tcp_ipv4, + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_4m, + setup_echo_srv_tcp_ipv4, + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_5m, + setup_echo_srv_tcp_ipv4, + teardown), + cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_6m, + setup_echo_srv_tcp_ipv4, + teardown), }; rc = cmocka_run_group_tests(tests, NULL, NULL); -- GitLab