From 7c488fcfe8a5fd17f99f1c88c29ce97f5851f786 Mon Sep 17 00:00:00 2001 From: "Zyad A. Ali" Date: Mon, 31 May 2021 17:31:40 +0200 Subject: Create package msgqueue. Create package msgqueue, define primitives to be used for message queues, and add a msgqueue.Registry to IPCNamespace. Updates #135 --- pkg/sentry/kernel/msgqueue/BUILD | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 pkg/sentry/kernel/msgqueue/BUILD (limited to 'pkg/sentry/kernel/msgqueue/BUILD') diff --git a/pkg/sentry/kernel/msgqueue/BUILD b/pkg/sentry/kernel/msgqueue/BUILD new file mode 100644 index 000000000..dfe937e78 --- /dev/null +++ b/pkg/sentry/kernel/msgqueue/BUILD @@ -0,0 +1,32 @@ +load("//tools:defs.bzl", "go_library") +load("//tools/go_generics:defs.bzl", "go_template_instance") + +package(licenses = ["notice"]) + +go_template_instance( + name = "message_list", + out = "message_list.go", + package = "msgqueue", + prefix = "msg", + template = "//pkg/ilist:generic_list", + types = { + "Element": "*Message", + "Linker": "*Message", + }, +) + +go_library( + name = "msgqueue", + srcs = [ + "msgqueue.go", + "message_list.go", + ], + visibility = ["//pkg/sentry:internal"], + deps = [ + "//pkg/sentry/kernel/auth", + "//pkg/sentry/kernel/ipc", + "//pkg/sentry/kernel/time", + "//pkg/waiter", + "//pkg/sync", + ], +) -- cgit v1.2.3 From 7eae6402c111323cd6e92e0499dfa12cf2554d1a Mon Sep 17 00:00:00 2001 From: "Zyad A. Ali" Date: Mon, 31 May 2021 21:07:47 +0200 Subject: Implement Registry.FindOrCreate. FindOrCreate implements the behaviour of msgget(2). Updates #135 --- pkg/sentry/kernel/msgqueue/BUILD | 7 ++- pkg/sentry/kernel/msgqueue/msgqueue.go | 93 +++++++++++++++++++++++++++++++--- 2 files changed, 93 insertions(+), 7 deletions(-) (limited to 'pkg/sentry/kernel/msgqueue/BUILD') diff --git a/pkg/sentry/kernel/msgqueue/BUILD b/pkg/sentry/kernel/msgqueue/BUILD index dfe937e78..4114ee45a 100644 --- a/pkg/sentry/kernel/msgqueue/BUILD +++ b/pkg/sentry/kernel/msgqueue/BUILD @@ -23,10 +23,15 @@ go_library( ], visibility = ["//pkg/sentry:internal"], deps = [ + "//pkg/abi/linux", + "//pkg/context", + "//pkg/errors/linuxerr", + "//pkg/log", + "//pkg/sentry/fs", "//pkg/sentry/kernel/auth", "//pkg/sentry/kernel/ipc", "//pkg/sentry/kernel/time", - "//pkg/waiter", "//pkg/sync", + "//pkg/waiter", ], ) diff --git a/pkg/sentry/kernel/msgqueue/msgqueue.go b/pkg/sentry/kernel/msgqueue/msgqueue.go index 51db8b12c..0e2d996a8 100644 --- a/pkg/sentry/kernel/msgqueue/msgqueue.go +++ b/pkg/sentry/kernel/msgqueue/msgqueue.go @@ -16,14 +16,28 @@ package msgqueue import ( - "sync" - + "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/context" + "gvisor.dev/gvisor/pkg/errors/linuxerr" + "gvisor.dev/gvisor/pkg/sentry/fs" "gvisor.dev/gvisor/pkg/sentry/kernel/auth" "gvisor.dev/gvisor/pkg/sentry/kernel/ipc" ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time" + "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/waiter" ) +const ( + // System-wide limit for maximum number of queues. + maxQueues = linux.MSGMNI + + // Maximum size of a queue in bytes. + maxQueueBytes = linux.MSGMNB + + // Maximum size of a message in bytes. + maxMessageBytes = linux.MSGMAX +) + // Registry contains a set of message queues that can be referenced using keys // or IDs. // @@ -36,6 +50,13 @@ type Registry struct { reg *ipc.Registry } +// NewRegistry returns a new Registry ready to be used. +func NewRegistry(userNS *auth.UserNamespace) *Registry { + return &Registry{ + reg: ipc.NewRegistry(userNS), + } +} + // Queue represents a SysV message queue, described by sysvipc(7). // // +stateify savable @@ -103,9 +124,69 @@ type Message struct { mSize uint64 } -// NewRegistry returns a new Registry ready to be used. -func NewRegistry(userNS *auth.UserNamespace) *Registry { - return &Registry{ - reg: ipc.NewRegistry(userNS), +// FindOrCreate creates a new message queue or returns an existing one. See +// msgget(2). +func (r *Registry) FindOrCreate(ctx context.Context, key ipc.Key, mode linux.FileMode, private, create, exclusive bool) (*Queue, error) { + r.mu.Lock() + defer r.mu.Unlock() + + if !private { + queue, err := r.reg.Find(ctx, key, mode, create, exclusive) + if err != nil { + return nil, err + } + + if queue != nil { + return queue.(*Queue), nil + } + } + + // Check system-wide limits. + if r.reg.ObjectCount() >= maxQueues { + return nil, linuxerr.ENOSPC } + + return r.newQueueLocked(ctx, key, fs.FileOwnerFromContext(ctx), fs.FilePermsFromMode(mode)) +} + +// newQueueLocked creates a new queue using the given fields. An error is +// returned if there're no more available identifiers. +// +// Precondition: r.mu must be held. +func (r *Registry) newQueueLocked(ctx context.Context, key ipc.Key, creator fs.FileOwner, perms fs.FilePermissions) (*Queue, error) { + q := &Queue{ + registry: r, + obj: ipc.NewObject(r.reg.UserNS, key, creator, creator, perms), + sendTime: ktime.ZeroTime, + receiveTime: ktime.ZeroTime, + changeTime: ktime.NowFromContext(ctx), + maxBytes: maxQueueBytes, + } + + err := r.reg.Register(q) + if err != nil { + return nil, err + } + return q, nil +} + +// Lock implements ipc.Mechanism.Lock. +func (q *Queue) Lock() { + q.mu.Lock() +} + +// Unlock implements ipc.mechanism.Unlock. +// +// +checklocksignore +func (q *Queue) Unlock() { + q.mu.Unlock() +} + +// Object implements ipc.Mechanism.Object. +func (q *Queue) Object() *ipc.Object { + return q.obj +} + +// Destroy implements ipc.Mechanism.Destroy. It's yet to be implemented. +func (q *Queue) Destroy() { } -- cgit v1.2.3 From 084aa4fa51b74b426cf1bc0e1347624b2b516bcd Mon Sep 17 00:00:00 2001 From: "Zyad A. Ali" Date: Wed, 2 Jun 2021 15:33:36 +0200 Subject: Implement Registry.Remove. Remove implements the behaviour or msgctl(IPC_RMID). Updates #135 --- pkg/sentry/kernel/msgqueue/BUILD | 1 - pkg/sentry/kernel/msgqueue/msgqueue.go | 25 ++++++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'pkg/sentry/kernel/msgqueue/BUILD') diff --git a/pkg/sentry/kernel/msgqueue/BUILD b/pkg/sentry/kernel/msgqueue/BUILD index 4114ee45a..e4305fead 100644 --- a/pkg/sentry/kernel/msgqueue/BUILD +++ b/pkg/sentry/kernel/msgqueue/BUILD @@ -26,7 +26,6 @@ go_library( "//pkg/abi/linux", "//pkg/context", "//pkg/errors/linuxerr", - "//pkg/log", "//pkg/sentry/fs", "//pkg/sentry/kernel/auth", "//pkg/sentry/kernel/ipc", diff --git a/pkg/sentry/kernel/msgqueue/msgqueue.go b/pkg/sentry/kernel/msgqueue/msgqueue.go index 0e2d996a8..5f7f35cd3 100644 --- a/pkg/sentry/kernel/msgqueue/msgqueue.go +++ b/pkg/sentry/kernel/msgqueue/msgqueue.go @@ -67,6 +67,11 @@ type Queue struct { // mu protects all the fields below. mu sync.Mutex `state:"nosave"` + // dead is set to true when a queue is removed from the registry and should + // not be used. Operations on the queue should check dead, and return + // EIDRM if set to true. + dead bool + // obj defines basic fields that should be included in all SysV IPC objects. obj *ipc.Object @@ -170,6 +175,17 @@ func (r *Registry) newQueueLocked(ctx context.Context, key ipc.Key, creator fs.F return q, nil } +// Remove removes the queue with specified ID. All waiters (readers and +// writers) and writers will be awakened and fail. Remove will return an error +// if the ID is invalid, or the the user doesn't have privileges. +func (r *Registry) Remove(id ipc.ID, creds *auth.Credentials) error { + r.mu.Lock() + defer r.mu.Unlock() + + r.reg.Remove(id, creds) + return nil +} + // Lock implements ipc.Mechanism.Lock. func (q *Queue) Lock() { q.mu.Lock() @@ -187,6 +203,13 @@ func (q *Queue) Object() *ipc.Object { return q.obj } -// Destroy implements ipc.Mechanism.Destroy. It's yet to be implemented. +// Destroy implements ipc.Mechanism.Destroy. func (q *Queue) Destroy() { + q.dead = true + + // Notify waiters. Senders and receivers will try to run, and return an + // error (EIDRM). Waiters should remove themselves from the queue after + // waking up. + q.senders.Notify(waiter.EventOut) + q.receivers.Notify(waiter.EventIn) } -- cgit v1.2.3