From c8851be593a7f0a8c22f53e44d2d46d71c3c142d Mon Sep 17 00:00:00 2001 From: "Zyad A. Ali" Date: Sun, 30 May 2021 18:03:39 +0200 Subject: Add initial test cases for msgget(2). Updates #135 --- test/syscalls/linux/BUILD | 12 ++++++ test/syscalls/linux/msgqueue.cc | 96 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 test/syscalls/linux/msgqueue.cc (limited to 'test/syscalls/linux') diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD index 5ca655803..773688f44 100644 --- a/test/syscalls/linux/BUILD +++ b/test/syscalls/linux/BUILD @@ -4170,6 +4170,18 @@ cc_binary( ], ) +cc_binary( + name = "msgqueue_test", + testonly = 1, + srcs = ["msgqueue.cc"], + linkstatic = 1, + deps = [ + "//test/util:temp_path", + "//test/util:test_main", + "//test/util:test_util", + ], +) + cc_binary( name = "fadvise64_test", testonly = 1, diff --git a/test/syscalls/linux/msgqueue.cc b/test/syscalls/linux/msgqueue.cc new file mode 100644 index 000000000..ba61bba34 --- /dev/null +++ b/test/syscalls/linux/msgqueue.cc @@ -0,0 +1,96 @@ +// 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 +#include +#include + +#include "test/util/temp_path.h" +#include "test/util/test_util.h" + +namespace gvisor { +namespace testing { +namespace { + +// Queue is a RAII class used to automatically clean message queues. +class Queue { + public: + explicit Queue(int id) : id_(id) {} + + ~Queue() { + if (id_ >= 0) { + EXPECT_THAT(msgctl(id_, IPC_RMID, nullptr), SyscallSucceeds()); + } + } + + int release() { + int old = id_; + id_ = -1; + return old; + } + + int get() { return id_; } + + private: + int id_ = -1; +}; + +// Test simple creation and retrieval for msgget(2). +TEST(MsgqueueTest, MsgGet) { + // Don't run test until syscall is implemented. + GTEST_SKIP(); + + const TempPath keyfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); + const key_t key = ftok(keyfile.path().c_str(), 1); + ASSERT_THAT(key, SyscallSucceeds()); + + Queue queue(msgget(key, IPC_CREAT)); + ASSERT_THAT(queue.get(), SyscallSucceeds()); + EXPECT_THAT(msgget(key, 0), SyscallSucceedsWithValue(queue.get())); +} + +// Test simple failure scenarios for msgget(2). +TEST(MsgqueueTest, MsgGetFail) { + // Don't run test until syscall is implemented. + GTEST_SKIP(); + + const TempPath keyfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); + const key_t key = ftok(keyfile.path().c_str(), 1); + ASSERT_THAT(key, SyscallSucceeds()); + + EXPECT_THAT(msgget(key, 0), SyscallFailsWithErrno(ENOENT)); + + Queue queue(msgget(key, IPC_CREAT)); + ASSERT_THAT(queue.get(), SyscallSucceeds()); + + EXPECT_THAT(msgget(key, IPC_CREAT | IPC_EXCL), SyscallFailsWithErrno(EEXIST)); +} + +// Test using msgget(2) with IPC_PRIVATE option. +TEST(MsgqueueTest, MsgGetIpcPrivate) { + // Don't run test until syscall is implemented. + GTEST_SKIP(); + + Queue queue1(msgget(IPC_PRIVATE, 0)); + ASSERT_THAT(queue1.get(), SyscallSucceeds()); + + Queue queue2(msgget(IPC_PRIVATE, 0)); + ASSERT_THAT(queue2.get(), SyscallSucceeds()); + + EXPECT_NE(queue1.get(), queue2.get()); +} + +} // namespace +} // namespace testing +} // namespace gvisor -- cgit v1.2.3 From 4a874557f5846ec9cb2e5b2515921e37a4ca4f07 Mon Sep 17 00:00:00 2001 From: "Zyad A. Ali" Date: Wed, 2 Jun 2021 15:54:36 +0200 Subject: Implement stubs for msgget(2) and msgctl(IPC_RMID). Add support for msgget, and msgctl(IPC_RMID), and enable msgqueue syscall tests. Updates #135 --- pkg/sentry/kernel/msgqueue/msgqueue.go | 5 +++ pkg/sentry/syscalls/linux/BUILD | 1 + pkg/sentry/syscalls/linux/linux64.go | 16 ++++----- pkg/sentry/syscalls/linux/sys_msgqueue.go | 57 +++++++++++++++++++++++++++++++ test/syscalls/linux/msgqueue.cc | 9 ----- 5 files changed, 71 insertions(+), 17 deletions(-) create mode 100644 pkg/sentry/syscalls/linux/sys_msgqueue.go (limited to 'test/syscalls/linux') diff --git a/pkg/sentry/kernel/msgqueue/msgqueue.go b/pkg/sentry/kernel/msgqueue/msgqueue.go index 5f7f35cd3..3ce926950 100644 --- a/pkg/sentry/kernel/msgqueue/msgqueue.go +++ b/pkg/sentry/kernel/msgqueue/msgqueue.go @@ -213,3 +213,8 @@ func (q *Queue) Destroy() { q.senders.Notify(waiter.EventOut) q.receivers.Notify(waiter.EventIn) } + +// ID returns queue's ID. +func (q *Queue) ID() ipc.ID { + return q.obj.ID +} diff --git a/pkg/sentry/syscalls/linux/BUILD b/pkg/sentry/syscalls/linux/BUILD index 7941b2be9..ccccce6a9 100644 --- a/pkg/sentry/syscalls/linux/BUILD +++ b/pkg/sentry/syscalls/linux/BUILD @@ -25,6 +25,7 @@ go_library( "sys_mempolicy.go", "sys_mmap.go", "sys_mount.go", + "sys_msgqueue.go", "sys_pipe.go", "sys_poll.go", "sys_prctl.go", diff --git a/pkg/sentry/syscalls/linux/linux64.go b/pkg/sentry/syscalls/linux/linux64.go index f1cb5a2c8..6f44d767b 100644 --- a/pkg/sentry/syscalls/linux/linux64.go +++ b/pkg/sentry/syscalls/linux/linux64.go @@ -121,10 +121,10 @@ var AMD64 = &kernel.SyscallTable{ 65: syscalls.PartiallySupported("semop", Semop, "Option SEM_UNDO not supported.", nil), 66: syscalls.Supported("semctl", Semctl), 67: syscalls.Supported("shmdt", Shmdt), - 68: syscalls.ErrorWithEvent("msgget", syserror.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921) - 69: syscalls.ErrorWithEvent("msgsnd", syserror.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921) - 70: syscalls.ErrorWithEvent("msgrcv", syserror.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921) - 71: syscalls.ErrorWithEvent("msgctl", syserror.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921) + 68: syscalls.Supported("msgget", Msgget), + 69: syscalls.ErrorWithEvent("msgsnd", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921) + 70: syscalls.ErrorWithEvent("msgrcv", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921) + 71: syscalls.PartiallySupported("msgctl", Msgctl, "Only supports IPC_RMID option.", []string{"gvisor.dev/issue/135"}), 72: syscalls.PartiallySupported("fcntl", Fcntl, "Not all options are supported.", nil), 73: syscalls.PartiallySupported("flock", Flock, "Locks are held within the sandbox only.", nil), 74: syscalls.PartiallySupported("fsync", Fsync, "Full data flush is not guaranteed at this time.", nil), @@ -616,10 +616,10 @@ var ARM64 = &kernel.SyscallTable{ 183: syscalls.ErrorWithEvent("mq_timedreceive", syserror.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // TODO(b/29354921) 184: syscalls.ErrorWithEvent("mq_notify", syserror.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // TODO(b/29354921) 185: syscalls.ErrorWithEvent("mq_getsetattr", syserror.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // TODO(b/29354921) - 186: syscalls.ErrorWithEvent("msgget", syserror.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921) - 187: syscalls.ErrorWithEvent("msgctl", syserror.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921) - 188: syscalls.ErrorWithEvent("msgrcv", syserror.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921) - 189: syscalls.ErrorWithEvent("msgsnd", syserror.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921) + 186: syscalls.Supported("msgget", Msgget), + 187: syscalls.PartiallySupported("msgctl", Msgctl, "Only supports IPC_RMID option.", []string{"gvisor.dev/issue/135"}), + 188: syscalls.ErrorWithEvent("msgrcv", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921) + 189: syscalls.ErrorWithEvent("msgsnd", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921) 190: syscalls.Supported("semget", Semget), 191: syscalls.Supported("semctl", Semctl), 192: syscalls.Supported("semtimedop", Semtimedop), diff --git a/pkg/sentry/syscalls/linux/sys_msgqueue.go b/pkg/sentry/syscalls/linux/sys_msgqueue.go new file mode 100644 index 000000000..3476e218d --- /dev/null +++ b/pkg/sentry/syscalls/linux/sys_msgqueue.go @@ -0,0 +1,57 @@ +// 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 linux + +import ( + "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/errors/linuxerr" + "gvisor.dev/gvisor/pkg/sentry/arch" + "gvisor.dev/gvisor/pkg/sentry/kernel" + "gvisor.dev/gvisor/pkg/sentry/kernel/auth" + "gvisor.dev/gvisor/pkg/sentry/kernel/ipc" +) + +// Msgget implements msgget(2). +func Msgget(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { + key := ipc.Key(args[0].Int()) + flag := args[1].Int() + + private := key == linux.IPC_PRIVATE + create := flag&linux.IPC_CREAT == linux.IPC_CREAT + exclusive := flag&linux.IPC_EXCL == linux.IPC_EXCL + mode := linux.FileMode(flag & 0777) + + r := t.IPCNamespace().MsgqueueRegistry() + queue, err := r.FindOrCreate(t, key, mode, private, create, exclusive) + if err != nil { + return 0, nil, err + } + return uintptr(queue.ID()), nil, nil +} + +// Msgctl implements msgctl(2). +func Msgctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { + id := ipc.ID(args[0].Int()) + cmd := args[1].Int() + + creds := auth.CredentialsFromContext(t) + + switch cmd { + case linux.IPC_RMID: + return 0, nil, t.IPCNamespace().MsgqueueRegistry().Remove(id, creds) + default: + return 0, nil, linuxerr.EINVAL + } +} diff --git a/test/syscalls/linux/msgqueue.cc b/test/syscalls/linux/msgqueue.cc index ba61bba34..2409de7e8 100644 --- a/test/syscalls/linux/msgqueue.cc +++ b/test/syscalls/linux/msgqueue.cc @@ -48,9 +48,6 @@ class Queue { // Test simple creation and retrieval for msgget(2). TEST(MsgqueueTest, MsgGet) { - // Don't run test until syscall is implemented. - GTEST_SKIP(); - const TempPath keyfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); const key_t key = ftok(keyfile.path().c_str(), 1); ASSERT_THAT(key, SyscallSucceeds()); @@ -62,9 +59,6 @@ TEST(MsgqueueTest, MsgGet) { // Test simple failure scenarios for msgget(2). TEST(MsgqueueTest, MsgGetFail) { - // Don't run test until syscall is implemented. - GTEST_SKIP(); - const TempPath keyfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); const key_t key = ftok(keyfile.path().c_str(), 1); ASSERT_THAT(key, SyscallSucceeds()); @@ -79,9 +73,6 @@ TEST(MsgqueueTest, MsgGetFail) { // Test using msgget(2) with IPC_PRIVATE option. TEST(MsgqueueTest, MsgGetIpcPrivate) { - // Don't run test until syscall is implemented. - GTEST_SKIP(); - Queue queue1(msgget(IPC_PRIVATE, 0)); ASSERT_THAT(queue1.get(), SyscallSucceeds()); -- cgit v1.2.3