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