diff options
-rw-r--r-- | pkg/sentry/kernel/msgqueue/msgqueue.go | 9 | ||||
-rw-r--r-- | pkg/sentry/syscalls/linux/BUILD | 1 | ||||
-rw-r--r-- | pkg/sentry/syscalls/linux/linux64.go | 8 | ||||
-rw-r--r-- | pkg/sentry/syscalls/linux/sys_msgqueue.go | 82 | ||||
-rw-r--r-- | test/syscalls/linux/msgqueue.cc | 50 |
5 files changed, 99 insertions, 51 deletions
diff --git a/pkg/sentry/kernel/msgqueue/msgqueue.go b/pkg/sentry/kernel/msgqueue/msgqueue.go index 21025797d..28520b19a 100644 --- a/pkg/sentry/kernel/msgqueue/msgqueue.go +++ b/pkg/sentry/kernel/msgqueue/msgqueue.go @@ -386,6 +386,15 @@ func (q *Queue) pop(ctx context.Context, creds *auth.Credentials, mType int64, m return msg, nil } +// Copy copies a message from the queue without deleting it. See +// msgrcv(MSG_COPY). +func (q *Queue) Copy() (*Message, error) { + q.mu.Lock() + defer q.mu.Unlock() + + return nil, linuxerr.ENOSYS +} + // msgOfType returns the first message with the specified type, nil if no // message is found. If except is true, the first message of a type not equal // to mType will be returned. diff --git a/pkg/sentry/syscalls/linux/BUILD b/pkg/sentry/syscalls/linux/BUILD index ccccce6a9..b5a371d9a 100644 --- a/pkg/sentry/syscalls/linux/BUILD +++ b/pkg/sentry/syscalls/linux/BUILD @@ -86,6 +86,7 @@ go_library( "//pkg/sentry/kernel/eventfd", "//pkg/sentry/kernel/fasync", "//pkg/sentry/kernel/ipc", + "//pkg/sentry/kernel/msgqueue", "//pkg/sentry/kernel/pipe", "//pkg/sentry/kernel/sched", "//pkg/sentry/kernel/shm", diff --git a/pkg/sentry/syscalls/linux/linux64.go b/pkg/sentry/syscalls/linux/linux64.go index 6f44d767b..6a5a30516 100644 --- a/pkg/sentry/syscalls/linux/linux64.go +++ b/pkg/sentry/syscalls/linux/linux64.go @@ -122,8 +122,8 @@ var AMD64 = &kernel.SyscallTable{ 66: syscalls.Supported("semctl", Semctl), 67: syscalls.Supported("shmdt", Shmdt), 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) + 69: syscalls.Supported("msgsnd", Msgsnd), + 70: syscalls.PartiallySupported("msgrcv", Msgrcv, "Doesn't support MSG_COPY option.", []string{"gvisor.dev/issue/135"}), 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), @@ -618,8 +618,8 @@ var ARM64 = &kernel.SyscallTable{ 185: syscalls.ErrorWithEvent("mq_getsetattr", syserror.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // 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) + 188: syscalls.PartiallySupported("msgrcv", Msgrcv, "Doesn't support MSG_COPY option.", []string{"gvisor.dev/issue/135"}), + 189: syscalls.Supported("msgsnd", Msgsnd), 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 index 3476e218d..d61777d02 100644 --- a/pkg/sentry/syscalls/linux/sys_msgqueue.go +++ b/pkg/sentry/syscalls/linux/sys_msgqueue.go @@ -17,10 +17,12 @@ package linux import ( "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/errors/linuxerr" + "gvisor.dev/gvisor/pkg/marshal/primitive" "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" + "gvisor.dev/gvisor/pkg/sentry/kernel/msgqueue" ) // Msgget implements msgget(2). @@ -41,6 +43,86 @@ func Msgget(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal return uintptr(queue.ID()), nil, nil } +// Msgsnd implements msgsnd(2). +func Msgsnd(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { + id := ipc.ID(args[0].Int()) + msgAddr := args[1].Pointer() + size := args[2].Int64() + flag := args[3].Int() + + if size < 0 || size > linux.MSGMAX { + return 0, nil, linuxerr.EINVAL + } + + wait := flag&linux.IPC_NOWAIT != linux.IPC_NOWAIT + pid := int32(t.ThreadGroup().ID()) + + buf := linux.MsgBuf{ + Text: make([]byte, size), + } + if _, err := buf.CopyIn(t, msgAddr); err != nil { + return 0, nil, err + } + + queue, err := t.IPCNamespace().MsgqueueRegistry().FindByID(id) + if err != nil { + return 0, nil, err + } + + msg := msgqueue.Message{ + Type: int64(buf.Type), + Text: buf.Text, + Size: uint64(size), + } + return 0, nil, queue.Send(t, msg, t, wait, pid) +} + +// Msgrcv implements msgrcv(2). +func Msgrcv(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { + id := ipc.ID(args[0].Int()) + msgAddr := args[1].Pointer() + size := args[2].Int64() + mType := args[3].Int64() + flag := args[4].Int() + + wait := flag&linux.IPC_NOWAIT != linux.IPC_NOWAIT + except := flag&linux.MSG_EXCEPT == linux.MSG_EXCEPT + truncate := flag&linux.MSG_NOERROR == linux.MSG_NOERROR + + msgCopy := flag&linux.MSG_COPY == linux.MSG_COPY + + msg, err := receive(t, id, mType, size, msgCopy, wait, truncate, except) + if err != nil { + return 0, nil, err + } + + buf := linux.MsgBuf{ + Type: primitive.Int64(msg.Type), + Text: msg.Text, + } + if _, err := buf.CopyOut(t, msgAddr); err != nil { + return 0, nil, err + } + return uintptr(msg.Size), nil, nil +} + +// receive returns a message from the queue with the given ID. If msgCopy is +// true, a message is copied from the queue without being removed. Otherwise, +// a message is removed from the queue and returned. +func receive(t *kernel.Task, id ipc.ID, mType int64, maxSize int64, msgCopy, wait, truncate, except bool) (*msgqueue.Message, error) { + pid := int32(t.ThreadGroup().ID()) + + queue, err := t.IPCNamespace().MsgqueueRegistry().FindByID(id) + if err != nil { + return nil, err + } + + if msgCopy { + return queue.Copy() + } + return queue.Receive(t, t, mType, maxSize, wait, truncate, except, pid) +} + // Msgctl implements msgctl(2). func Msgctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { id := ipc.ID(args[0].Int()) diff --git a/test/syscalls/linux/msgqueue.cc b/test/syscalls/linux/msgqueue.cc index 95eeb2ef9..28dbd6056 100644 --- a/test/syscalls/linux/msgqueue.cc +++ b/test/syscalls/linux/msgqueue.cc @@ -26,11 +26,6 @@ namespace gvisor { namespace testing { namespace { -// run is a temporary variable to easily enable/disable running tests. This -// variable should be removed along with SKIP_IF when the tested functionality -// is enabled. -constexpr bool run = false; - constexpr int msgMax = 8192; // Max size for message in bytes. constexpr int msgMni = 32000; // Max number of identifiers. constexpr int msgMnb = 16384; // Default max size of message queue in bytes. @@ -115,8 +110,6 @@ TEST(MsgqueueTest, MsgGetIpcPrivate) { // Test simple msgsnd and msgrcv. TEST(MsgqueueTest, MsgOpSimple) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -133,8 +126,6 @@ TEST(MsgqueueTest, MsgOpSimple) { // Test msgsnd and msgrcv of an empty message. TEST(MsgqueueTest, MsgOpEmpty) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -148,8 +139,6 @@ TEST(MsgqueueTest, MsgOpEmpty) { // Test truncation of message with MSG_NOERROR flag. TEST(MsgqueueTest, MsgOpTruncate) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -165,8 +154,6 @@ TEST(MsgqueueTest, MsgOpTruncate) { // Test msgsnd and msgrcv using invalid arguments. TEST(MsgqueueTest, MsgOpInvalidArgs) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -185,12 +172,10 @@ TEST(MsgqueueTest, MsgOpInvalidArgs) { // Test non-blocking msgrcv with an empty queue. TEST(MsgqueueTest, MsgOpNoMsg) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); - msgbuf rcv{1, ""}; + msgbuf rcv; EXPECT_THAT(msgrcv(queue.get(), &rcv, sizeof(rcv.mtext) + 1, 0, IPC_NOWAIT), SyscallFailsWithErrno(ENOMSG)); } @@ -198,8 +183,6 @@ TEST(MsgqueueTest, MsgOpNoMsg) { // Test non-blocking msgrcv with a non-empty queue, but no messages of wanted // type. TEST(MsgqueueTest, MsgOpNoMsgType) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -213,8 +196,6 @@ TEST(MsgqueueTest, MsgOpNoMsgType) { // Test msgrcv with a larger size message than wanted, and truncation disabled. TEST(MsgqueueTest, MsgOpTooBig) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -228,8 +209,6 @@ TEST(MsgqueueTest, MsgOpTooBig) { // Test receiving messages based on type. TEST(MsgqueueTest, MsgRcvType) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -257,8 +236,6 @@ TEST(MsgqueueTest, MsgRcvType) { // Test using MSG_EXCEPT to receive a different-type message. TEST(MsgqueueTest, MsgExcept) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -285,8 +262,6 @@ TEST(MsgqueueTest, MsgExcept) { // Test msgrcv with a negative type. TEST(MsgqueueTest, MsgRcvTypeNegative) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -309,8 +284,6 @@ TEST(MsgqueueTest, MsgRcvTypeNegative) { // Test permission-related failure scenarios. TEST(MsgqueueTest, MsgOpPermissions) { - SKIP_IF(!run); - AutoCapability cap(CAP_IPC_OWNER, false); Queue queue(msgget(IPC_PRIVATE, 0000)); @@ -326,8 +299,6 @@ TEST(MsgqueueTest, MsgOpPermissions) { // Test limits for messages and queues. TEST(MsgqueueTest, MsgOpLimits) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -376,8 +347,6 @@ bool MsgCopySupported() { // Test usage of MSG_COPY for msgrcv. TEST(MsgqueueTest, MsgCopy) { - SKIP_IF(!run); - SKIP_IF(!MsgCopySupported()); Queue queue(msgget(IPC_PRIVATE, 0600)); @@ -419,8 +388,6 @@ TEST(MsgqueueTest, MsgCopy) { // Test msgrcv (most probably) blocking on an empty queue. TEST(MsgqueueTest, MsgRcvBlocking) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -449,8 +416,6 @@ TEST(MsgqueueTest, MsgRcvBlocking) { // Test msgrcv (most probably) waiting for a specific-type message. TEST(MsgqueueTest, MsgRcvTypeBlocking) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -487,8 +452,6 @@ TEST(MsgqueueTest, MsgRcvTypeBlocking) { // Test msgsnd (most probably) blocking on a full queue. TEST(MsgqueueTest, MsgSndBlocking) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -508,8 +471,7 @@ TEST(MsgqueueTest, MsgSndBlocking) { if (child_pid == 0) { // Fill the queue. for (size_t i = 0; i < msgCount; i++) { - EXPECT_THAT(msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0), - SyscallSucceeds()); + TEST_PCHECK(msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0) == 0); } // Next msgsnd should block. @@ -531,7 +493,7 @@ TEST(MsgqueueTest, MsgSndBlocking) { // Delay a bit more for the blocking msgsnd. absl::SleepFor(absl::Milliseconds(100)); - EXPECT_THAT(msgrcv(queue.get(), &rcv, sizeof(buf.mtext) + 1, 0, 0), + EXPECT_THAT(msgrcv(queue.get(), &rcv, sizeof(buf.mtext), 0, 0), SyscallSucceedsWithValue(sizeof(buf.mtext))); int status; @@ -542,8 +504,6 @@ TEST(MsgqueueTest, MsgSndBlocking) { // Test removing a queue while a blocking msgsnd is executing. TEST(MsgqueueTest, MsgSndRmWhileBlocking) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -592,8 +552,6 @@ TEST(MsgqueueTest, MsgSndRmWhileBlocking) { // Test removing a queue while a blocking msgrcv is executing. TEST(MsgqueueTest, MsgRcvRmWhileBlocking) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); @@ -620,8 +578,6 @@ TEST(MsgqueueTest, MsgRcvRmWhileBlocking) { // Test a collection of msgsnd/msgrcv operations in different processes. TEST(MsgqueueTest, MsgOpGeneral) { - SKIP_IF(!run); - Queue queue(msgget(IPC_PRIVATE, 0600)); ASSERT_THAT(queue.get(), SyscallSucceeds()); |