summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorZyad A. Ali <zyad.ali.me@gmail.com>2021-06-21 13:48:25 +0200
committerZyad A. Ali <zyad.ali.me@gmail.com>2021-08-03 18:13:24 +0200
commiteb638ee583ba29a879202451692fadfed7c3fdd0 (patch)
tree7f4ad90d8602d4d468d50019081fbf5368ebc38e
parent930984a1aa82caa21e87f4fb60dd457e61ab890b (diff)
Implement stubs for msgsnd(2) and msgrcv(2).
Add support for msgsnd and msgrcv and enable syscall tests. Updates #135
-rw-r--r--pkg/sentry/kernel/msgqueue/msgqueue.go9
-rw-r--r--pkg/sentry/syscalls/linux/BUILD1
-rw-r--r--pkg/sentry/syscalls/linux/linux64.go8
-rw-r--r--pkg/sentry/syscalls/linux/sys_msgqueue.go82
-rw-r--r--test/syscalls/linux/msgqueue.cc50
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());