github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/pkg/sentry/syscalls/linux/sys_shm.go (about) 1 // Copyright 2018 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 "github.com/MerlinKodo/gvisor/pkg/abi/linux" 19 "github.com/MerlinKodo/gvisor/pkg/errors/linuxerr" 20 "github.com/MerlinKodo/gvisor/pkg/sentry/arch" 21 "github.com/MerlinKodo/gvisor/pkg/sentry/kernel" 22 "github.com/MerlinKodo/gvisor/pkg/sentry/kernel/ipc" 23 "github.com/MerlinKodo/gvisor/pkg/sentry/kernel/shm" 24 ) 25 26 // Shmget implements shmget(2). 27 func Shmget(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 28 key := ipc.Key(args[0].Int()) 29 size := uint64(args[1].SizeT()) 30 flag := args[2].Int() 31 32 private := key == linux.IPC_PRIVATE 33 create := flag&linux.IPC_CREAT == linux.IPC_CREAT 34 exclusive := flag&linux.IPC_EXCL == linux.IPC_EXCL 35 mode := linux.FileMode(flag & 0777) 36 37 pid := int32(t.ThreadGroup().ID()) 38 r := t.IPCNamespace().ShmRegistry() 39 segment, err := r.FindOrCreate(t, pid, key, size, mode, private, create, exclusive) 40 if err != nil { 41 return 0, nil, err 42 } 43 defer segment.DecRef(t) 44 return uintptr(segment.ID()), nil, nil 45 } 46 47 // findSegment retrives a shm segment by the given id. 48 // 49 // findSegment returns a reference on Shm. 50 func findSegment(t *kernel.Task, id ipc.ID) (*shm.Shm, error) { 51 r := t.IPCNamespace().ShmRegistry() 52 segment := r.FindByID(id) 53 if segment == nil { 54 // No segment with provided id. 55 return nil, linuxerr.EINVAL 56 } 57 return segment, nil 58 } 59 60 // Shmat implements shmat(2). 61 func Shmat(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 62 id := ipc.ID(args[0].Int()) 63 addr := args[1].Pointer() 64 flag := args[2].Int() 65 66 segment, err := findSegment(t, id) 67 if err != nil { 68 return 0, nil, linuxerr.EINVAL 69 } 70 defer segment.DecRef(t) 71 72 opts, err := segment.ConfigureAttach(t, addr, shm.AttachOpts{ 73 Execute: flag&linux.SHM_EXEC == linux.SHM_EXEC, 74 Readonly: flag&linux.SHM_RDONLY == linux.SHM_RDONLY, 75 Remap: flag&linux.SHM_REMAP == linux.SHM_REMAP, 76 }) 77 if err != nil { 78 return 0, nil, err 79 } 80 addr, err = t.MemoryManager().MMap(t, opts) 81 return uintptr(addr), nil, err 82 } 83 84 // Shmdt implements shmdt(2). 85 func Shmdt(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 86 addr := args[0].Pointer() 87 err := t.MemoryManager().DetachShm(t, addr) 88 return 0, nil, err 89 } 90 91 // Shmctl implements shmctl(2). 92 func Shmctl(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 93 id := ipc.ID(args[0].Int()) 94 cmd := args[1].Int() 95 buf := args[2].Pointer() 96 97 r := t.IPCNamespace().ShmRegistry() 98 99 switch cmd { 100 case linux.SHM_STAT: 101 // Technically, we should be treating id as "an index into the kernel's 102 // internal array that maintains information about all shared memory 103 // segments on the system". Since we don't track segments in an array, 104 // we'll just pretend the shmid is the index and do the same thing as 105 // IPC_STAT. Linux also uses the index as the shmid. 106 fallthrough 107 case linux.IPC_STAT: 108 segment, err := findSegment(t, id) 109 if err != nil { 110 return 0, nil, linuxerr.EINVAL 111 } 112 defer segment.DecRef(t) 113 114 stat, err := segment.IPCStat(t) 115 if err == nil { 116 _, err = stat.CopyOut(t, buf) 117 } 118 return 0, nil, err 119 120 case linux.IPC_INFO: 121 params := r.IPCInfo() 122 _, err := params.CopyOut(t, buf) 123 return 0, nil, err 124 125 case linux.SHM_INFO: 126 info := r.ShmInfo() 127 _, err := info.CopyOut(t, buf) 128 return 0, nil, err 129 } 130 131 // Remaining commands refer to a specific segment. 132 segment, err := findSegment(t, id) 133 if err != nil { 134 return 0, nil, linuxerr.EINVAL 135 } 136 defer segment.DecRef(t) 137 138 switch cmd { 139 case linux.IPC_SET: 140 var ds linux.ShmidDS 141 if _, err = ds.CopyIn(t, buf); err != nil { 142 return 0, nil, err 143 } 144 err := segment.Set(t, &ds) 145 return 0, nil, err 146 147 case linux.IPC_RMID: 148 segment.MarkDestroyed(t) 149 return 0, nil, nil 150 151 case linux.SHM_LOCK, linux.SHM_UNLOCK: 152 // We currently do not support memory locking anywhere. 153 // mlock(2)/munlock(2) are currently stubbed out as no-ops so do the 154 // same here. 155 t.Kernel().EmitUnimplementedEvent(t, sysno) 156 return 0, nil, nil 157 158 default: 159 return 0, nil, linuxerr.EINVAL 160 } 161 }