diff options
author | Zyad A. Ali <zyad.ali.me@gmail.com> | 2021-08-05 22:12:16 +0200 |
---|---|---|
committer | Zyad A. Ali <zyad.ali.me@gmail.com> | 2021-09-15 21:56:35 +0200 |
commit | 2774b3ea3bcae10afa8c87e1fce46d60e7580fe1 (patch) | |
tree | eaf27c00ae6ffdbd6854bc5c81874f5292221db0 | |
parent | fc8819f43cae94db8345060f0af00e013dc86098 (diff) |
Test read(2), poll(2), mount(2), and unshare(2) for message queues.
Updates #136
-rw-r--r-- | test/syscalls/linux/BUILD | 3 | ||||
-rw-r--r-- | test/syscalls/linux/mq.cc | 152 |
2 files changed, 155 insertions, 0 deletions
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD index ed2adfbc9..8d501a3a3 100644 --- a/test/syscalls/linux/BUILD +++ b/test/syscalls/linux/BUILD @@ -4179,6 +4179,9 @@ cc_binary( "-lrt", ], deps = [ + "//test/util:capability_util", + "//test/util:fs_util", + "//test/util:mount_util", "//test/util:posix_error", "//test/util:test_main", "//test/util:temp_path", diff --git a/test/syscalls/linux/mq.cc b/test/syscalls/linux/mq.cc index 610d41fb6..9a4a87dfe 100644 --- a/test/syscalls/linux/mq.cc +++ b/test/syscalls/linux/mq.cc @@ -14,11 +14,16 @@ #include <fcntl.h> #include <mqueue.h> +#include <sched.h> +#include <sys/poll.h> #include <sys/stat.h> #include <unistd.h> #include <string> +#include "test/util/capability_util.h" +#include "test/util/fs_util.h" +#include "test/util/mount_util.h" #include "test/util/posix_error.h" #include "test/util/temp_path.h" #include "test/util/test_util.h" @@ -229,6 +234,153 @@ TEST(MqTest, OpenWriteAccess) { queue.release(); } +// Test changing IPC namespace. +TEST(MqTest, ChangeIpcNamespace) { + GTEST_SKIP(); + SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); + + // When changing IPC namespaces, Linux doesn't invalidate or close the + // previously opened file descriptions and allows operations to be performed + // on them normally, until they're closed. + // + // To test this we create a new queue, use unshare(CLONE_NEWIPC) to change + // into a new IPC namespace, and trying performing a read(2) on the queue. + PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE( + MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr)); + + // As mq_unlink(2) uses queue's name, it should fail after changing IPC + // namespace. To clean the queue, we should unlink it now, this should not + // cause a problem, as the queue presists until the last mq_close(2). + ASSERT_NO_ERRNO(MqUnlink(queue.name())); + + ASSERT_THAT(unshare(CLONE_NEWIPC), SyscallSucceeds()); + + const size_t msgSize = 60; + char queueRead[msgSize]; + ASSERT_THAT(read(queue.fd(), &queueRead[0], msgSize - 1), SyscallSucceeds()); + + ASSERT_NO_ERRNO(MqClose(queue.release())); + + // Unlinking should fail now after changing IPC namespace. + EXPECT_THAT(MqUnlink(queue.name()), PosixErrorIs(ENOENT)); +} + +// Test mounting the mqueue filesystem. +TEST(MqTest, Mount) { + GTEST_SKIP(); + SKIP_IF(IsRunningWithVFS1() || + !ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); + + PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE( + MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr)); + + auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + ASSERT_NO_ERRNO(Mount("none", dir.path(), "mqueue", 0, "", 0)); +} + +// Test mounting the mqueue filesystem to several places. +TEST(MqTest, MountSeveral) { + GTEST_SKIP(); + SKIP_IF(IsRunningWithVFS1() || + !ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); + + PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE( + MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr)); + + auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + // Assign the pointer so it doesn't get destroyed before the second mount is + // created. + auto mnt = + ASSERT_NO_ERRNO_AND_VALUE(Mount("none", dir1.path(), "mqueue", 0, "", 0)); + + auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + ASSERT_NO_ERRNO(Mount("none", dir2.path(), "mqueue", 0, "", 0)); +} + +// Test mounting mqueue and opening a queue as normal file. +TEST(MqTest, OpenAsFile) { + GTEST_SKIP(); + SKIP_IF(IsRunningWithVFS1() || + !ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); + + PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE( + MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr)); + + auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + auto mnt = + ASSERT_NO_ERRNO_AND_VALUE(Mount("none", dir.path(), "mqueue", 0, "", 0)); + + // Open queue using open(2). + auto fd = ASSERT_NO_ERRNO_AND_VALUE( + Open(JoinPath(dir.path(), queue.name()), O_RDONLY)); + + const size_t msgSize = 60; + char queueRead[msgSize]; + queueRead[msgSize - 1] = '\0'; + + ASSERT_THAT(read(fd.get(), &queueRead[0], msgSize - 1), SyscallSucceeds()); + + std::string want( + "QSIZE:0 NOTIFY:0 SIGNO:0 NOTIFY_PID:0 "); + std::string got(queueRead); + EXPECT_EQ(got, want); +} + +// Test removing a queue using unlink(2). +TEST(MqTest, UnlinkAsFile) { + GTEST_SKIP(); + SKIP_IF(IsRunningWithVFS1() || + !ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); + + PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE( + MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr)); + + auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + auto mnt = + ASSERT_NO_ERRNO_AND_VALUE(Mount("none", dir.path(), "mqueue", 0, "", 0)); + + ASSERT_NO_ERRNO( + UnlinkAt(FileDescriptor(), JoinPath(dir.path(), queue.name()), 0)); + + // Trying to unlink again should fail. + EXPECT_THAT(MqUnlink(queue.name()), PosixErrorIs(ENOENT)); + queue.release(); +} + +// Test read(2) from an empty queue. +TEST(MqTest, ReadEmpty) { + GTEST_SKIP(); + + PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE( + MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr)); + + const size_t msgSize = 60; + char queueRead[msgSize]; + queueRead[msgSize - 1] = '\0'; + + ASSERT_THAT(read(queue.fd(), &queueRead[0], msgSize - 1), SyscallSucceeds()); + + std::string want( + "QSIZE:0 NOTIFY:0 SIGNO:0 NOTIFY_PID:0 "); + std::string got(queueRead); + EXPECT_EQ(got, want); +} + +// Test poll(2) on an empty queue. +TEST(MqTest, PollEmpty) { + GTEST_SKIP(); + + PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE( + MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr)); + + struct pollfd pfd; + pfd.fd = queue.fd(); + pfd.events = POLLOUT | POLLIN | POLLRDNORM | POLLWRNORM; + + ASSERT_THAT(poll(&pfd, 1, -1), SyscallSucceeds()); + ASSERT_EQ(pfd.revents, POLLOUT | POLLWRNORM); +} + } // namespace } // namespace testing } // namespace gvisor |