summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorZyad A. Ali <zyad.ali.me@gmail.com>2021-08-03 07:48:24 +0200
committerZyad A. Ali <zyad.ali.me@gmail.com>2021-09-28 20:43:52 +0200
commitf03dc73f0f46d0ff1ae209fefc98ee3d7fc725d2 (patch)
treeee84a03ddfd6c96c8be7d2a4050caf2875127fb9
parent9bde727f4f2e5b7cf52211a3a4fe71c7a0e4f1ea (diff)
Implement stubs for mq_open(2) and mq_unlink(2).
Support mq_open and mq_unlink, and enable syscall tests. Updates #136
-rw-r--r--pkg/sentry/syscalls/linux/vfs2/BUILD2
-rw-r--r--pkg/sentry/syscalls/linux/vfs2/mq.go98
-rw-r--r--pkg/sentry/syscalls/linux/vfs2/vfs2.go5
-rw-r--r--test/syscalls/linux/mq.cc22
4 files changed, 113 insertions, 14 deletions
diff --git a/pkg/sentry/syscalls/linux/vfs2/BUILD b/pkg/sentry/syscalls/linux/vfs2/BUILD
index 1e3bd2a50..4a03008f8 100644
--- a/pkg/sentry/syscalls/linux/vfs2/BUILD
+++ b/pkg/sentry/syscalls/linux/vfs2/BUILD
@@ -19,6 +19,7 @@ go_library(
"memfd.go",
"mmap.go",
"mount.go",
+ "mq.go",
"path.go",
"pipe.go",
"poll.go",
@@ -59,6 +60,7 @@ go_library(
"//pkg/sentry/kernel",
"//pkg/sentry/kernel/auth",
"//pkg/sentry/kernel/fasync",
+ "//pkg/sentry/kernel/mq",
"//pkg/sentry/kernel/pipe",
"//pkg/sentry/kernel/time",
"//pkg/sentry/limits",
diff --git a/pkg/sentry/syscalls/linux/vfs2/mq.go b/pkg/sentry/syscalls/linux/vfs2/mq.go
new file mode 100644
index 000000000..d5d81c6e2
--- /dev/null
+++ b/pkg/sentry/syscalls/linux/vfs2/mq.go
@@ -0,0 +1,98 @@
+// 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.
+
+package vfs2
+
+import (
+ "gvisor.dev/gvisor/pkg/abi/linux"
+ "gvisor.dev/gvisor/pkg/sentry/arch"
+ "gvisor.dev/gvisor/pkg/sentry/kernel"
+ "gvisor.dev/gvisor/pkg/sentry/kernel/mq"
+)
+
+// MqOpen implements mq_open(2).
+func MqOpen(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
+ nameAddr := args[0].Pointer()
+ flag := args[1].Int()
+ mode := args[2].ModeT()
+ attrAddr := args[3].Pointer()
+
+ name, err := t.CopyInString(nameAddr, mq.MaxName)
+ if err != nil {
+ return 0, nil, err
+ }
+
+ rOnly := flag&linux.O_RDONLY == linux.O_RDONLY
+ wOnly := flag&linux.O_WRONLY == linux.O_WRONLY
+ readWrite := flag&linux.O_RDWR == linux.O_RDWR
+
+ create := flag&linux.O_CREAT == linux.O_CREAT
+ exclusive := flag&linux.O_EXCL == linux.O_EXCL
+ block := flag&linux.O_NONBLOCK != linux.O_NONBLOCK
+
+ var attr linux.MqAttr
+ var attrPtr *linux.MqAttr
+ if attrAddr != 0 {
+ if _, err := attr.CopyIn(t, attrAddr); err != nil {
+ return 0, nil, err
+ }
+ attrPtr = &attr
+ }
+
+ opts := openOpts(name, rOnly, wOnly, readWrite, create, exclusive, block)
+
+ r := t.IPCNamespace().PosixQueues()
+ queue, err := r.FindOrCreate(t, opts, linux.FileMode(mode), attrPtr)
+ if err != nil {
+ return 0, nil, err
+ }
+
+ fd, err := t.NewFDFromVFS2(0, queue, kernel.FDFlags{
+ CloseOnExec: flag&linux.O_CLOEXEC != 0,
+ })
+ if err != nil {
+ return 0, nil, err
+ }
+ return uintptr(fd), nil, nil
+}
+
+// MqUnlink implements mq_unlink(2).
+func MqUnlink(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
+ nameAddr := args[0].Pointer()
+ name, err := t.CopyInString(nameAddr, mq.MaxName)
+ if err != nil {
+ return 0, nil, err
+ }
+ return 0, nil, t.IPCNamespace().PosixQueues().Remove(t, name)
+}
+
+func openOpts(name string, rOnly, wOnly, readWrite, create, exclusive, block bool) mq.OpenOpts {
+ var access mq.AccessType
+ switch {
+ case readWrite:
+ access = mq.ReadWrite
+ case wOnly:
+ access = mq.WriteOnly
+ case rOnly:
+ access = mq.ReadOnly
+ }
+
+ return mq.OpenOpts{
+ Name: name,
+ Access: access,
+ Create: create,
+ Exclusive: exclusive,
+ Block: block,
+ }
+}
diff --git a/pkg/sentry/syscalls/linux/vfs2/vfs2.go b/pkg/sentry/syscalls/linux/vfs2/vfs2.go
index 0fc81e694..4eb15a7f2 100644
--- a/pkg/sentry/syscalls/linux/vfs2/vfs2.go
+++ b/pkg/sentry/syscalls/linux/vfs2/vfs2.go
@@ -112,6 +112,8 @@ func Override() {
s.Table[232] = syscalls.Supported("epoll_wait", EpollWait)
s.Table[233] = syscalls.Supported("epoll_ctl", EpollCtl)
s.Table[235] = syscalls.Supported("utimes", Utimes)
+ s.Table[240] = syscalls.Supported("mq_open", MqOpen)
+ s.Table[241] = syscalls.Supported("mq_unlink", MqUnlink)
s.Table[253] = syscalls.PartiallySupported("inotify_init", InotifyInit, "inotify events are only available inside the sandbox.", nil)
s.Table[254] = syscalls.PartiallySupported("inotify_add_watch", InotifyAddWatch, "inotify events are only available inside the sandbox.", nil)
s.Table[255] = syscalls.PartiallySupported("inotify_rm_watch", InotifyRmWatch, "inotify events are only available inside the sandbox.", nil)
@@ -241,6 +243,8 @@ func Override() {
s.Table[86] = syscalls.Supported("timerfd_settime", TimerfdSettime)
s.Table[87] = syscalls.Supported("timerfd_gettime", TimerfdGettime)
s.Table[88] = syscalls.Supported("utimensat", Utimensat)
+ s.Table[180] = syscalls.Supported("mq_open", MqOpen)
+ s.Table[181] = syscalls.Supported("mq_unlink", MqUnlink)
s.Table[198] = syscalls.Supported("socket", Socket)
s.Table[199] = syscalls.Supported("socketpair", SocketPair)
s.Table[200] = syscalls.Supported("bind", Bind)
@@ -271,6 +275,5 @@ func Override() {
s.Table[287] = syscalls.Supported("pwritev2", Pwritev2)
s.Table[291] = syscalls.Supported("statx", Statx)
s.Table[441] = syscalls.Supported("epoll_pwait2", EpollPwait2)
-
s.Init()
}
diff --git a/test/syscalls/linux/mq.cc b/test/syscalls/linux/mq.cc
index 9a4a87dfe..b3cd6d1b9 100644
--- a/test/syscalls/linux/mq.cc
+++ b/test/syscalls/linux/mq.cc
@@ -121,14 +121,14 @@ PosixError MqClose(mqd_t fd) {
// Test simple opening and closing of a message queue.
TEST(MqTest, Open) {
- GTEST_SKIP();
+ SKIP_IF(IsRunningWithVFS1());
EXPECT_THAT(MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr),
IsPosixErrorOkAndHolds(_));
}
// Test mq_open(2) after mq_unlink(2).
TEST(MqTest, OpenAfterUnlink) {
- GTEST_SKIP();
+ SKIP_IF(IsRunningWithVFS1());
PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE(
MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr));
@@ -140,7 +140,7 @@ TEST(MqTest, OpenAfterUnlink) {
// Test using invalid args with mq_open.
TEST(MqTest, OpenInvalidArgs) {
- GTEST_SKIP();
+ SKIP_IF(IsRunningWithVFS1());
// Name must start with a slash.
EXPECT_THAT(MqOpen("test", O_RDWR), PosixErrorIs(EINVAL));
@@ -180,7 +180,7 @@ TEST(MqTest, OpenInvalidArgs) {
// Test creating a queue that already exists.
TEST(MqTest, CreateAlreadyExists) {
- GTEST_SKIP();
+ SKIP_IF(IsRunningWithVFS1());
PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE(
MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr));
@@ -191,7 +191,7 @@ TEST(MqTest, CreateAlreadyExists) {
// Test opening a queue that doesn't exists.
TEST(MqTest, NoQueueExists) {
- GTEST_SKIP();
+ 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),
@@ -236,8 +236,8 @@ TEST(MqTest, OpenWriteAccess) {
// Test changing IPC namespace.
TEST(MqTest, ChangeIpcNamespace) {
- GTEST_SKIP();
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
+ 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
@@ -267,7 +267,6 @@ TEST(MqTest, ChangeIpcNamespace) {
// Test mounting the mqueue filesystem.
TEST(MqTest, Mount) {
- GTEST_SKIP();
SKIP_IF(IsRunningWithVFS1() ||
!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
@@ -280,7 +279,6 @@ TEST(MqTest, Mount) {
// 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)));
@@ -299,7 +297,6 @@ TEST(MqTest, MountSeveral) {
// 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)));
@@ -328,7 +325,6 @@ TEST(MqTest, OpenAsFile) {
// Test removing a queue using unlink(2).
TEST(MqTest, UnlinkAsFile) {
- GTEST_SKIP();
SKIP_IF(IsRunningWithVFS1() ||
!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
@@ -349,7 +345,7 @@ TEST(MqTest, UnlinkAsFile) {
// Test read(2) from an empty queue.
TEST(MqTest, ReadEmpty) {
- GTEST_SKIP();
+ SKIP_IF(IsRunningWithVFS1());
PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE(
MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr));
@@ -368,7 +364,7 @@ TEST(MqTest, ReadEmpty) {
// Test poll(2) on an empty queue.
TEST(MqTest, PollEmpty) {
- GTEST_SKIP();
+ SKIP_IF(IsRunningWithVFS1());
PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE(
MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr));