gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/syscalls/linux/sys_msgqueue.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 linux 16 17 import ( 18 "gvisor.dev/gvisor/pkg/abi/linux" 19 "gvisor.dev/gvisor/pkg/errors/linuxerr" 20 "gvisor.dev/gvisor/pkg/marshal/primitive" 21 "gvisor.dev/gvisor/pkg/sentry/arch" 22 "gvisor.dev/gvisor/pkg/sentry/kernel" 23 "gvisor.dev/gvisor/pkg/sentry/kernel/auth" 24 "gvisor.dev/gvisor/pkg/sentry/kernel/ipc" 25 "gvisor.dev/gvisor/pkg/sentry/kernel/msgqueue" 26 ) 27 28 // Msgget implements msgget(2). 29 func Msgget(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 30 key := ipc.Key(args[0].Int()) 31 flag := args[1].Int() 32 33 private := key == linux.IPC_PRIVATE 34 create := flag&linux.IPC_CREAT == linux.IPC_CREAT 35 exclusive := flag&linux.IPC_EXCL == linux.IPC_EXCL 36 mode := linux.FileMode(flag & 0777) 37 38 r := t.IPCNamespace().MsgqueueRegistry() 39 queue, err := r.FindOrCreate(t, key, mode, private, create, exclusive) 40 if err != nil { 41 return 0, nil, err 42 } 43 return uintptr(queue.ID()), nil, nil 44 } 45 46 // Msgsnd implements msgsnd(2). 47 func Msgsnd(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 48 id := ipc.ID(args[0].Int()) 49 msgAddr := args[1].Pointer() 50 size := args[2].Int64() 51 flag := args[3].Int() 52 53 if size < 0 || size > linux.MSGMAX { 54 return 0, nil, linuxerr.EINVAL 55 } 56 57 wait := flag&linux.IPC_NOWAIT != linux.IPC_NOWAIT 58 pid := int32(t.ThreadGroup().ID()) 59 60 buf := linux.MsgBuf{ 61 Text: make([]byte, size), 62 } 63 if _, err := buf.CopyIn(t, msgAddr); err != nil { 64 return 0, nil, err 65 } 66 67 queue, err := t.IPCNamespace().MsgqueueRegistry().FindByID(id) 68 if err != nil { 69 return 0, nil, err 70 } 71 72 msg := msgqueue.Message{ 73 Type: int64(buf.Type), 74 Text: buf.Text, 75 Size: uint64(size), 76 } 77 return 0, nil, queue.Send(t, msg, t, wait, pid) 78 } 79 80 // Msgrcv implements msgrcv(2). 81 func Msgrcv(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 82 id := ipc.ID(args[0].Int()) 83 msgAddr := args[1].Pointer() 84 size := args[2].Int64() 85 mType := args[3].Int64() 86 flag := args[4].Int() 87 88 wait := flag&linux.IPC_NOWAIT != linux.IPC_NOWAIT 89 except := flag&linux.MSG_EXCEPT == linux.MSG_EXCEPT 90 truncate := flag&linux.MSG_NOERROR == linux.MSG_NOERROR 91 92 msgCopy := flag&linux.MSG_COPY == linux.MSG_COPY 93 94 msg, err := receive(t, id, mType, size, msgCopy, wait, truncate, except) 95 if err != nil { 96 return 0, nil, err 97 } 98 99 buf := linux.MsgBuf{ 100 Type: primitive.Int64(msg.Type), 101 Text: msg.Text, 102 } 103 if _, err := buf.CopyOut(t, msgAddr); err != nil { 104 return 0, nil, err 105 } 106 return uintptr(msg.Size), nil, nil 107 } 108 109 // receive returns a message from the queue with the given ID. If msgCopy is 110 // true, a message is copied from the queue without being removed. Otherwise, 111 // a message is removed from the queue and returned. 112 func receive(t *kernel.Task, id ipc.ID, mType int64, maxSize int64, msgCopy, wait, truncate, except bool) (*msgqueue.Message, error) { 113 pid := int32(t.ThreadGroup().ID()) 114 115 queue, err := t.IPCNamespace().MsgqueueRegistry().FindByID(id) 116 if err != nil { 117 return nil, err 118 } 119 120 if msgCopy { 121 if wait || except { 122 return nil, linuxerr.EINVAL 123 } 124 return queue.Copy(mType) 125 } 126 return queue.Receive(t, t, mType, maxSize, wait, truncate, except, pid) 127 } 128 129 // Msgctl implements msgctl(2). 130 func Msgctl(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 131 id := ipc.ID(args[0].Int()) 132 cmd := args[1].Int() 133 buf := args[2].Pointer() 134 135 creds := auth.CredentialsFromContext(t) 136 137 r := t.IPCNamespace().MsgqueueRegistry() 138 139 switch cmd { 140 case linux.IPC_INFO: 141 info := r.IPCInfo(t) 142 _, err := info.CopyOut(t, buf) 143 return 0, nil, err 144 case linux.MSG_INFO: 145 msgInfo := r.MsgInfo(t) 146 _, err := msgInfo.CopyOut(t, buf) 147 return 0, nil, err 148 case linux.IPC_RMID: 149 return 0, nil, r.Remove(id, creds) 150 } 151 152 // Remaining commands use a queue. 153 queue, err := r.FindByID(id) 154 if err != nil { 155 return 0, nil, err 156 } 157 158 switch cmd { 159 case linux.MSG_STAT: 160 // Technically, we should be treating id as "an index into the kernel's 161 // internal array that maintains information about all shared memory 162 // segments on the system". Since we don't track segments in an array, 163 // we'll just pretend the msqid is the index and do the same thing as 164 // IPC_STAT. Linux also uses the index as the msqid. 165 fallthrough 166 case linux.IPC_STAT: 167 stat, err := queue.Stat(t) 168 if err != nil { 169 return 0, nil, err 170 } 171 _, err = stat.CopyOut(t, buf) 172 return 0, nil, err 173 174 case linux.MSG_STAT_ANY: 175 stat, err := queue.StatAny(t) 176 if err != nil { 177 return 0, nil, err 178 } 179 _, err = stat.CopyOut(t, buf) 180 return 0, nil, err 181 182 case linux.IPC_SET: 183 var ds linux.MsqidDS 184 if _, err := ds.CopyIn(t, buf); err != nil { 185 return 0, nil, linuxerr.EINVAL 186 } 187 err := queue.Set(t, &ds) 188 return 0, nil, err 189 190 default: 191 return 0, nil, linuxerr.EINVAL 192 } 193 }