summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux/mq.cc
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls/linux/mq.cc')
-rw-r--r--test/syscalls/linux/mq.cc395
1 files changed, 0 insertions, 395 deletions
diff --git a/test/syscalls/linux/mq.cc b/test/syscalls/linux/mq.cc
deleted file mode 100644
index 013994fd9..000000000
--- a/test/syscalls/linux/mq.cc
+++ /dev/null
@@ -1,395 +0,0 @@
-// Copyright 2021 The gVisor Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#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/cleanup.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"
-
-#define NAME_MAX 255
-
-namespace gvisor {
-namespace testing {
-namespace {
-
-// PosixQueue is a RAII class used to automatically clean POSIX message queues.
-class PosixQueue {
- public:
- PosixQueue(mqd_t fd, std::string name) : fd_(fd), name_(std::string(name)) {}
- PosixQueue(const PosixQueue&) = delete;
- PosixQueue& operator=(const PosixQueue&) = delete;
-
- // Move constructor.
- PosixQueue(PosixQueue&& q) {
- fd_ = q.fd_;
- name_ = q.name_;
- // Call PosixQueue::release, to prevent the object being released from
- // unlinking the underlying queue.
- q.release();
- }
-
- ~PosixQueue() {
- if (fd_ != -1) {
- EXPECT_THAT(mq_close(fd_), SyscallSucceeds());
- EXPECT_THAT(mq_unlink(name_.c_str()), SyscallSucceeds());
- }
- }
-
- mqd_t fd() { return fd_; }
-
- const char* name() { return name_.c_str(); }
-
- mqd_t release() {
- mqd_t old = fd_;
- fd_ = -1;
- return old;
- }
-
- private:
- mqd_t fd_;
- std::string name_;
-};
-
-// MqOpen wraps mq_open(3) using a given name.
-PosixErrorOr<PosixQueue> MqOpen(std::string name, int oflag) {
- mqd_t fd = mq_open(name.c_str(), oflag);
- if (fd == -1) {
- return PosixError(errno, absl::StrFormat("mq_open(%s, %d)", name, oflag));
- }
- return PosixQueue(fd, name);
-}
-
-// MqOpen wraps mq_open(3) using a given name.
-PosixErrorOr<PosixQueue> MqOpen(int oflag, mode_t mode, struct mq_attr* attr) {
- auto name = "/" + NextTempBasename();
- mqd_t fd = mq_open(name.c_str(), oflag, mode, attr);
- if (fd == -1) {
- return PosixError(errno, absl::StrFormat("mq_open(%d)", oflag));
- }
- return PosixQueue(fd, name);
-}
-
-// MqOpen wraps mq_open(3) using a generated name.
-PosixErrorOr<PosixQueue> MqOpen(std::string name, int oflag, mode_t mode,
- struct mq_attr* attr) {
- mqd_t fd = mq_open(name.c_str(), oflag, mode, attr);
- if (fd == -1) {
- return PosixError(errno, absl::StrFormat("mq_open(%d)", oflag));
- }
- return PosixQueue(fd, name);
-}
-
-// MqUnlink wraps mq_unlink(2).
-PosixError MqUnlink(std::string name) {
- int err = mq_unlink(name.c_str());
- if (err == -1) {
- return PosixError(errno, absl::StrFormat("mq_unlink(%s)", name.c_str()));
- }
- return NoError();
-}
-
-// MqClose wraps mq_close(2).
-PosixError MqClose(mqd_t fd) {
- int err = mq_close(fd);
- if (err == -1) {
- return PosixError(errno, absl::StrFormat("mq_close(%d)", fd));
- }
- return NoError();
-}
-
-// Test simple opening and closing of a message queue.
-TEST(MqTest, Open) {
- SKIP_IF(IsRunningWithVFS1());
- ASSERT_NO_ERRNO(MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr));
-}
-
-TEST(MqTest, ModeWithFileType) {
- SKIP_IF(IsRunningWithVFS1());
- // S_IFIFO should be ignored.
- ASSERT_NO_ERRNO(MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777 | S_IFIFO, nullptr));
-}
-
-// Test mq_open(2) after mq_unlink(2).
-TEST(MqTest, OpenAfterUnlink) {
- SKIP_IF(IsRunningWithVFS1());
-
- PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE(
- MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr));
-
- ASSERT_NO_ERRNO(MqUnlink(queue.name()));
- EXPECT_THAT(MqOpen(queue.name(), O_RDWR), PosixErrorIs(ENOENT));
- ASSERT_NO_ERRNO(MqClose(queue.release()));
-}
-
-// Test using invalid args with mq_open.
-TEST(MqTest, OpenInvalidArgs) {
- SKIP_IF(IsRunningWithVFS1());
-
- // Name must start with a slash.
- EXPECT_THAT(MqOpen("test", O_RDWR), PosixErrorIs(EINVAL));
-
- // Name can't contain more that one slash.
- EXPECT_THAT(MqOpen("/test/name", O_RDWR), PosixErrorIs(EACCES));
-
- // Both "." and ".." can't be used as queue names.
- EXPECT_THAT(MqOpen(".", O_RDWR), PosixErrorIs(EINVAL));
- EXPECT_THAT(MqOpen("..", O_RDWR), PosixErrorIs(EINVAL));
-
- // mq_attr's mq_maxmsg and mq_msgsize must be > 0.
- struct mq_attr attr;
- attr.mq_maxmsg = -1;
- attr.mq_msgsize = 10;
-
- EXPECT_THAT(MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, &attr),
- PosixErrorIs(EINVAL));
-
- attr.mq_maxmsg = 10;
- attr.mq_msgsize = -1;
-
- EXPECT_THAT(MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, &attr),
- PosixErrorIs(EINVAL));
-
- // Names should be shorter than NAME_MAX.
- char max[NAME_MAX + 3];
- max[0] = '/';
- for (size_t i = 1; i < NAME_MAX + 2; i++) {
- max[i] = 'a';
- }
- max[NAME_MAX + 2] = '\0';
-
- EXPECT_THAT(MqOpen(std::string(max), O_RDWR | O_CREAT | O_EXCL, 0777, &attr),
- PosixErrorIs(ENAMETOOLONG));
-}
-
-// Test creating a queue that already exists.
-TEST(MqTest, CreateAlreadyExists) {
- SKIP_IF(IsRunningWithVFS1());
-
- PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE(
- MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr));
-
- EXPECT_THAT(MqOpen(queue.name(), O_RDWR | O_CREAT | O_EXCL, 0777, nullptr),
- PosixErrorIs(EEXIST));
-}
-
-// Test opening a queue that doesn't exists.
-TEST(MqTest, NoQueueExists) {
- SKIP_IF(IsRunningWithVFS1());
-
- // Choose a name to pass that's unlikely to exist if the test is run locally.
- EXPECT_THAT(MqOpen("/gvisor-mq-test-nonexistent-queue", O_RDWR),
- PosixErrorIs(ENOENT));
-}
-
-// Test trying to re-open a queue with invalid permissions.
-TEST(MqTest, OpenNoAccess) {
- SKIP_IF(IsRunningWithVFS1());
-
- PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE(
- MqOpen(O_RDWR | O_CREAT | O_EXCL, 0000, nullptr));
-
- EXPECT_THAT(MqOpen(queue.name(), O_RDONLY), PosixErrorIs(EACCES));
- EXPECT_THAT(MqOpen(queue.name(), O_WRONLY), PosixErrorIs(EACCES));
- EXPECT_THAT(MqOpen(queue.name(), O_RDWR), PosixErrorIs(EACCES));
-}
-
-// Test trying to re-open a read-only queue for write.
-TEST(MqTest, OpenReadAccess) {
- SKIP_IF(IsRunningWithVFS1());
-
- PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE(
- MqOpen(O_RDWR | O_CREAT | O_EXCL, 0400, nullptr));
-
- EXPECT_THAT(MqOpen(queue.name(), O_WRONLY), PosixErrorIs(EACCES));
- EXPECT_NO_ERRNO(MqOpen(queue.name(), O_RDONLY));
- queue.release();
-}
-
-// Test trying to re-open a write-only queue for read.
-TEST(MqTest, OpenWriteAccess) {
- SKIP_IF(IsRunningWithVFS1());
-
- PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE(
- MqOpen(O_RDWR | O_CREAT | O_EXCL, 0200, nullptr));
-
- EXPECT_THAT(MqOpen(queue.name(), O_RDONLY), PosixErrorIs(EACCES));
- EXPECT_NO_ERRNO(MqOpen(queue.name(), O_WRONLY));
- queue.release();
-}
-
-// Test changing IPC namespace.
-TEST(MqTest, ChangeIpcNamespace) {
- SKIP_IF(IsRunningWithVFS1() ||
- !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) {
- 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) {
- SKIP_IF(IsRunningWithVFS1() ||
- !ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
- constexpr int numMounts = 3;
-
- // mountDirs should outlive mountCUs and queue so that its destructor succeeds
- // in unlinking the mountpoints and does not interfere with queue destruction.
- testing::TempPath mountDirs[numMounts];
- testing::Cleanup mountCUs[numMounts];
- PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE(
- MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr));
-
- for (int i = 0; i < numMounts; ++i) {
- mountDirs[i] = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
- mountCUs[i] = ASSERT_NO_ERRNO_AND_VALUE(
- Mount("none", mountDirs[i].path(), "mqueue", 0, "", 0));
- }
-
- // Ensure that queue is visible from all mounts.
- for (int i = 0; i < numMounts; ++i) {
- ASSERT_NO_ERRNO(Stat(JoinPath(mountDirs[i].path(), queue.name())));
- }
-}
-
-// Test mounting mqueue and opening a queue as normal file.
-TEST(MqTest, OpenAsFile) {
- 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) {
- 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) {
- SKIP_IF(IsRunningWithVFS1());
-
- 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) {
- SKIP_IF(IsRunningWithVFS1());
-
- 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