github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/fsimpl/mqfs/queue.go (about) 1 // Copyright 2021 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mqfs 16 17 import ( 18 "github.com/nicocha30/gvisor-ligolo/pkg/abi/linux" 19 "github.com/nicocha30/gvisor-ligolo/pkg/context" 20 "github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr" 21 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/fsimpl/kernfs" 22 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel/auth" 23 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel/mq" 24 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/vfs" 25 "github.com/nicocha30/gvisor-ligolo/pkg/usermem" 26 "github.com/nicocha30/gvisor-ligolo/pkg/waiter" 27 ) 28 29 // queueInode represents an inode for a message queue (/dev/mqueue/[name]). 30 // 31 // +stateify savable 32 type queueInode struct { 33 kernfs.DynamicBytesFile 34 35 // queue is the message queue backing this inode. 36 queue *mq.Queue 37 } 38 39 var _ kernfs.Inode = (*queueInode)(nil) 40 41 // newQueueInode returns a new, initialized queueInode. 42 func (fs *filesystem) newQueueInode(ctx context.Context, creds *auth.Credentials, q *mq.Queue, perm linux.FileMode) kernfs.Inode { 43 inode := &queueInode{queue: q} 44 inode.Init(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), q, perm) 45 return inode 46 } 47 48 // Keep implements kernfs.Inode.Keep. 49 func (q *queueInode) Keep() bool { 50 // Return true so that the fs keeps newly created dentries. This is done 51 // because inodes returned by root.Lookup are not temporary, they exist 52 // in the fs, and refer to message queues. 53 return true 54 } 55 56 // queueFD implements vfs.FileDescriptionImpl for FD backed by a POSIX message 57 // queue. It's mostly similar to DynamicBytesFD, but implements more operations. 58 // 59 // +stateify savable 60 type queueFD struct { 61 vfs.FileDescriptionDefaultImpl 62 vfs.DynamicBytesFileDescriptionImpl 63 vfs.LockFD 64 65 vfsfd vfs.FileDescription 66 inode kernfs.Inode 67 68 // queue is a view into the queue backing this fd. 69 queue mq.View 70 } 71 72 // Init initializes a queueFD. Mostly copied from DynamicBytesFD.Init, but uses 73 // the queueFD as FileDescriptionImpl. 74 func (fd *queueFD) Init(m *vfs.Mount, d *kernfs.Dentry, data vfs.DynamicBytesSource, locks *vfs.FileLocks, flags uint32) error { 75 fd.LockFD.Init(locks) 76 if err := fd.vfsfd.Init(fd, flags, m, d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil { 77 return err 78 } 79 fd.inode = d.Inode() 80 fd.DynamicBytesFileDescriptionImpl.Init(&fd.vfsfd, data) 81 return nil 82 } 83 84 // Seek implements vfs.FileDescriptionImpl.Seek. 85 func (fd *queueFD) Seek(ctx context.Context, offset int64, whence int32) (int64, error) { 86 return fd.DynamicBytesFileDescriptionImpl.Seek(ctx, offset, whence) 87 } 88 89 // Read implements vfs.FileDescriptionImpl.Read. 90 func (fd *queueFD) Read(ctx context.Context, dst usermem.IOSequence, opts vfs.ReadOptions) (int64, error) { 91 return fd.DynamicBytesFileDescriptionImpl.Read(ctx, dst, opts) 92 } 93 94 // PRead implements vfs.FileDescriptionImpl.PRead. 95 func (fd *queueFD) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts vfs.ReadOptions) (int64, error) { 96 return fd.DynamicBytesFileDescriptionImpl.PRead(ctx, dst, offset, opts) 97 } 98 99 // Write implements vfs.FileDescriptionImpl.Write. 100 func (fd *queueFD) Write(ctx context.Context, src usermem.IOSequence, opts vfs.WriteOptions) (int64, error) { 101 return fd.DynamicBytesFileDescriptionImpl.Write(ctx, src, opts) 102 } 103 104 // PWrite implements vfs.FileDescriptionImpl.PWrite. 105 func (fd *queueFD) PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts vfs.WriteOptions) (int64, error) { 106 return fd.DynamicBytesFileDescriptionImpl.PWrite(ctx, src, offset, opts) 107 } 108 109 // Release implements vfs.FileDescriptionImpl.Release. 110 func (fd *queueFD) Release(context.Context) {} 111 112 // Stat implements vfs.FileDescriptionImpl.Stat. 113 func (fd *queueFD) Stat(ctx context.Context, opts vfs.StatOptions) (linux.Statx, error) { 114 fs := fd.vfsfd.VirtualDentry().Mount().Filesystem() 115 return fd.inode.Stat(ctx, fs, opts) 116 } 117 118 // SetStat implements vfs.FileDescriptionImpl.SetStat. 119 func (fd *queueFD) SetStat(context.Context, vfs.SetStatOptions) error { 120 // DynamicBytesFiles are immutable. 121 return linuxerr.EPERM 122 } 123 124 // OnClose implements FileDescriptionImpl.OnClose similar to 125 // ipc/mqueue.c::mqueue_flush_file. 126 func (fd *queueFD) OnClose(ctx context.Context) error { 127 fd.queue.Flush(ctx) 128 return nil 129 } 130 131 // Readiness implements waiter.Waitable.Readiness similar to 132 // ipc/mqueue.c::mqueue_poll_file. 133 func (fd *queueFD) Readiness(mask waiter.EventMask) waiter.EventMask { 134 return fd.queue.Readiness(mask) 135 } 136 137 // EventRegister implements Waitable.EventRegister. 138 func (fd *queueFD) EventRegister(e *waiter.Entry) error { 139 return fd.queue.EventRegister(e) 140 } 141 142 // EventUnregister implements Waitable.EventUnregister. 143 func (fd *queueFD) EventUnregister(e *waiter.Entry) { 144 fd.queue.EventUnregister(e) 145 } 146 147 // Epollable implements FileDescriptionImpl.Epollable. 148 func (fd *queueFD) Epollable() bool { 149 return true 150 }