diff options
author | Filipe Brandenburger <filbranden@google.com> | 2018-07-24 20:15:55 -0700 |
---|---|---|
committer | Lukáš Nykrýn <lnykryn@redhat.com> | 2019-05-03 13:00:29 +0200 |
commit | 8798fcef9052d2946637fa2d4376844fad6b5f8c (patch) | |
tree | bbba93773bce178b972d321d1da246500e1616cb | |
parent | 814bb6a8bc39e0f9900d84e564759a3a8698fb04 (diff) | |
download | systemd-8798fcef9052d2946637fa2d4376844fad6b5f8c.tar.gz |
test-socket-util: Add tests for receive_fd_iov() and friends.
Test it when sending an FD without any contents, or an FD and some contents,
or only contents and no FD (using a bare send().)
Also fix the previous test which forked but was missing an _exit() at the
end of the child execution code.
(cherry picked from commit 8a3386ab4fea9c4efa9c72e7c149cf510a46f03e)
Resolves: #1683319
-rw-r--r-- | src/test/test-socket-util.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 588485d881..19c5395b92 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -6,8 +6,11 @@ #include "alloc-util.h" #include "async.h" +#include "exit-status.h" #include "fd-util.h" +#include "fileio.h" #include "in-addr-util.h" +#include "io-util.h" #include "log.h" #include "macro.h" #include "process-util.h" @@ -484,9 +487,215 @@ static void test_getpeercred_getpeergroups(void) { } safe_close_pair(pair); + _exit(EXIT_SUCCESS); } } +static void test_passfd_read(void) { + static const char file_contents[] = "test contents for passfd"; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + int r; + + assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0); + + r = safe_fork("(passfd_read)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + assert_se(r >= 0); + + if (r == 0) { + /* Child */ + char tmpfile[] = "/tmp/test-socket-util-passfd-read-XXXXXX"; + _cleanup_close_ int tmpfd = -1; + + pair[0] = safe_close(pair[0]); + + tmpfd = mkostemp_safe(tmpfile); + assert_se(tmpfd >= 0); + assert_se(write(tmpfd, file_contents, strlen(file_contents)) == (ssize_t) strlen(file_contents)); + tmpfd = safe_close(tmpfd); + + tmpfd = open(tmpfile, O_RDONLY); + assert_se(tmpfd >= 0); + assert_se(unlink(tmpfile) == 0); + + assert_se(send_one_fd(pair[1], tmpfd, MSG_DONTWAIT) == 0); + _exit(EXIT_SUCCESS); + } + + /* Parent */ + char buf[64]; + struct iovec iov = IOVEC_INIT(buf, sizeof(buf)-1); + _cleanup_close_ int fd = -1; + + pair[1] = safe_close(pair[1]); + + assert_se(receive_one_fd_iov(pair[0], &iov, 1, MSG_DONTWAIT, &fd) == 0); + + assert_se(fd >= 0); + r = read(fd, buf, sizeof(buf)-1); + assert_se(r >= 0); + buf[r] = 0; + assert_se(streq(buf, file_contents)); +} + +static void test_passfd_contents_read(void) { + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + static const char file_contents[] = "test contents in the file"; + static const char wire_contents[] = "test contents on the wire"; + int r; + + assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0); + + r = safe_fork("(passfd_contents_read)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + assert_se(r >= 0); + + if (r == 0) { + /* Child */ + struct iovec iov = IOVEC_INIT_STRING(wire_contents); + char tmpfile[] = "/tmp/test-socket-util-passfd-contents-read-XXXXXX"; + _cleanup_close_ int tmpfd = -1; + + pair[0] = safe_close(pair[0]); + + tmpfd = mkostemp_safe(tmpfile); + assert_se(tmpfd >= 0); + assert_se(write(tmpfd, file_contents, strlen(file_contents)) == (ssize_t) strlen(file_contents)); + tmpfd = safe_close(tmpfd); + + tmpfd = open(tmpfile, O_RDONLY); + assert_se(tmpfd >= 0); + assert_se(unlink(tmpfile) == 0); + + assert_se(send_one_fd_iov(pair[1], tmpfd, &iov, 1, MSG_DONTWAIT) > 0); + _exit(EXIT_SUCCESS); + } + + /* Parent */ + char buf[64]; + struct iovec iov = IOVEC_INIT(buf, sizeof(buf)-1); + _cleanup_close_ int fd = -1; + ssize_t k; + + pair[1] = safe_close(pair[1]); + + k = receive_one_fd_iov(pair[0], &iov, 1, MSG_DONTWAIT, &fd); + assert_se(k > 0); + buf[k] = 0; + assert_se(streq(buf, wire_contents)); + + assert_se(fd >= 0); + r = read(fd, buf, sizeof(buf)-1); + assert_se(r >= 0); + buf[r] = 0; + assert_se(streq(buf, file_contents)); +} + +static void test_receive_nopassfd(void) { + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + static const char wire_contents[] = "no fd passed here"; + int r; + + assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0); + + r = safe_fork("(receive_nopassfd)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + assert_se(r >= 0); + + if (r == 0) { + /* Child */ + struct iovec iov = IOVEC_INIT_STRING(wire_contents); + + pair[0] = safe_close(pair[0]); + + assert_se(send_one_fd_iov(pair[1], -1, &iov, 1, MSG_DONTWAIT) > 0); + _exit(EXIT_SUCCESS); + } + + /* Parent */ + char buf[64]; + struct iovec iov = IOVEC_INIT(buf, sizeof(buf)-1); + int fd = -999; + ssize_t k; + + pair[1] = safe_close(pair[1]); + + k = receive_one_fd_iov(pair[0], &iov, 1, MSG_DONTWAIT, &fd); + assert_se(k > 0); + buf[k] = 0; + assert_se(streq(buf, wire_contents)); + + /* no fd passed here, confirm it was reset */ + assert_se(fd == -1); +} + +static void test_send_nodata_nofd(void) { + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + int r; + + assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0); + + r = safe_fork("(send_nodata_nofd)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + assert_se(r >= 0); + + if (r == 0) { + /* Child */ + pair[0] = safe_close(pair[0]); + + assert_se(send_one_fd_iov(pair[1], -1, NULL, 0, MSG_DONTWAIT) == -EINVAL); + _exit(EXIT_SUCCESS); + } + + /* Parent */ + char buf[64]; + struct iovec iov = IOVEC_INIT(buf, sizeof(buf)-1); + int fd = -999; + ssize_t k; + + pair[1] = safe_close(pair[1]); + + k = receive_one_fd_iov(pair[0], &iov, 1, MSG_DONTWAIT, &fd); + /* recvmsg() will return errno EAGAIN if nothing was sent */ + assert_se(k == -EAGAIN); + + /* receive_one_fd_iov returned error, so confirm &fd wasn't touched */ + assert_se(fd == -999); +} + +static void test_send_emptydata(void) { + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + int r; + + assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0); + + r = safe_fork("(send_emptydata)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + assert_se(r >= 0); + + if (r == 0) { + /* Child */ + struct iovec iov = IOVEC_INIT_STRING(""); /* zero-length iov */ + assert_se(iov.iov_len == 0); + + pair[0] = safe_close(pair[0]); + + /* This will succeed, since iov is set. */ + assert_se(send_one_fd_iov(pair[1], -1, &iov, 1, MSG_DONTWAIT) == 0); + _exit(EXIT_SUCCESS); + } + + /* Parent */ + char buf[64]; + struct iovec iov = IOVEC_INIT(buf, sizeof(buf)-1); + int fd = -999; + ssize_t k; + + pair[1] = safe_close(pair[1]); + + k = receive_one_fd_iov(pair[0], &iov, 1, MSG_DONTWAIT, &fd); + /* receive_one_fd_iov() returns -EIO if an fd is not found and no data was returned. */ + assert_se(k == -EIO); + + /* receive_one_fd_iov returned error, so confirm &fd wasn't touched */ + assert_se(fd == -999); +} + int main(int argc, char *argv[]) { log_set_max_level(LOG_DEBUG); @@ -515,5 +724,11 @@ int main(int argc, char *argv[]) { test_getpeercred_getpeergroups(); + test_passfd_read(); + test_passfd_contents_read(); + test_receive_nopassfd(); + test_send_nodata_nofd(); + test_send_emptydata(); + return 0; } |