github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/syscalls/linux/sys_prctl.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 "fmt" 19 20 "github.com/nicocha30/gvisor-ligolo/pkg/abi/linux" 21 "github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr" 22 "github.com/nicocha30/gvisor-ligolo/pkg/marshal/primitive" 23 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch" 24 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel" 25 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel/auth" 26 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/mm" 27 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/vfs" 28 ) 29 30 // Prctl implements linux syscall prctl(2). 31 // It has a list of subfunctions which operate on the process. The arguments are 32 // all based on each subfunction. 33 func Prctl(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 34 option := args[0].Int() 35 36 switch option { 37 case linux.PR_SET_PDEATHSIG: 38 sig := linux.Signal(args[1].Int()) 39 if sig != 0 && !sig.IsValid() { 40 return 0, nil, linuxerr.EINVAL 41 } 42 t.SetParentDeathSignal(sig) 43 return 0, nil, nil 44 45 case linux.PR_GET_PDEATHSIG: 46 _, err := primitive.CopyInt32Out(t, args[1].Pointer(), int32(t.ParentDeathSignal())) 47 return 0, nil, err 48 49 case linux.PR_GET_DUMPABLE: 50 d := t.MemoryManager().Dumpability() 51 switch d { 52 case mm.NotDumpable: 53 return linux.SUID_DUMP_DISABLE, nil, nil 54 case mm.UserDumpable: 55 return linux.SUID_DUMP_USER, nil, nil 56 case mm.RootDumpable: 57 return linux.SUID_DUMP_ROOT, nil, nil 58 default: 59 panic(fmt.Sprintf("Unknown dumpability %v", d)) 60 } 61 62 case linux.PR_SET_DUMPABLE: 63 var d mm.Dumpability 64 switch args[1].Int() { 65 case linux.SUID_DUMP_DISABLE: 66 d = mm.NotDumpable 67 case linux.SUID_DUMP_USER: 68 d = mm.UserDumpable 69 default: 70 // N.B. Userspace may not pass SUID_DUMP_ROOT. 71 return 0, nil, linuxerr.EINVAL 72 } 73 t.MemoryManager().SetDumpability(d) 74 return 0, nil, nil 75 76 case linux.PR_GET_KEEPCAPS: 77 if t.Credentials().KeepCaps { 78 return 1, nil, nil 79 } 80 81 return 0, nil, nil 82 83 case linux.PR_SET_KEEPCAPS: 84 val := args[1].Int() 85 // prctl(2): arg2 must be either 0 (permitted capabilities are cleared) 86 // or 1 (permitted capabilities are kept). 87 if val == 0 { 88 t.SetKeepCaps(false) 89 } else if val == 1 { 90 t.SetKeepCaps(true) 91 } else { 92 return 0, nil, linuxerr.EINVAL 93 } 94 95 return 0, nil, nil 96 97 case linux.PR_SET_NAME: 98 addr := args[1].Pointer() 99 name, err := t.CopyInString(addr, linux.TASK_COMM_LEN-1) 100 if err != nil && !linuxerr.Equals(linuxerr.ENAMETOOLONG, err) { 101 return 0, nil, err 102 } 103 t.SetName(name) 104 105 case linux.PR_GET_NAME: 106 addr := args[1].Pointer() 107 buf := t.CopyScratchBuffer(linux.TASK_COMM_LEN) 108 len := copy(buf, t.Name()) 109 if len < linux.TASK_COMM_LEN { 110 buf[len] = 0 111 len++ 112 } 113 _, err := t.CopyOutBytes(addr, buf[:len]) 114 if err != nil { 115 return 0, nil, err 116 } 117 118 case linux.PR_SET_MM: 119 if !t.HasCapability(linux.CAP_SYS_RESOURCE) { 120 return 0, nil, linuxerr.EPERM 121 } 122 123 switch args[1].Int() { 124 case linux.PR_SET_MM_EXE_FILE: 125 fd := args[2].Int() 126 127 file := t.GetFile(fd) 128 if file == nil { 129 return 0, nil, linuxerr.EBADF 130 } 131 defer file.DecRef(t) 132 133 // They trying to set exe to a non-file? 134 stat, err := file.Stat(t, vfs.StatOptions{Mask: linux.STATX_TYPE}) 135 if err != nil { 136 return 0, nil, err 137 } 138 if stat.Mask&linux.STATX_TYPE == 0 || stat.Mode&linux.FileTypeMask != linux.ModeRegular { 139 return 0, nil, linuxerr.EBADF 140 } 141 142 // Set the underlying executable. 143 t.MemoryManager().SetExecutable(t, file) 144 145 case linux.PR_SET_MM_AUXV, 146 linux.PR_SET_MM_START_CODE, 147 linux.PR_SET_MM_END_CODE, 148 linux.PR_SET_MM_START_DATA, 149 linux.PR_SET_MM_END_DATA, 150 linux.PR_SET_MM_START_STACK, 151 linux.PR_SET_MM_START_BRK, 152 linux.PR_SET_MM_BRK, 153 linux.PR_SET_MM_ARG_START, 154 linux.PR_SET_MM_ARG_END, 155 linux.PR_SET_MM_ENV_START, 156 linux.PR_SET_MM_ENV_END: 157 158 t.Kernel().EmitUnimplementedEvent(t, sysno) 159 fallthrough 160 default: 161 return 0, nil, linuxerr.EINVAL 162 } 163 164 case linux.PR_SET_NO_NEW_PRIVS: 165 if args[1].Int() != 1 || args[2].Int() != 0 || args[3].Int() != 0 || args[4].Int() != 0 { 166 return 0, nil, linuxerr.EINVAL 167 } 168 // PR_SET_NO_NEW_PRIVS is assumed to always be set. 169 // See kernel.Task.updateCredsForExecLocked. 170 return 0, nil, nil 171 172 case linux.PR_GET_NO_NEW_PRIVS: 173 if args[1].Int() != 0 || args[2].Int() != 0 || args[3].Int() != 0 || args[4].Int() != 0 { 174 return 0, nil, linuxerr.EINVAL 175 } 176 return 1, nil, nil 177 178 case linux.PR_SET_PTRACER: 179 pid := args[1].Int() 180 switch pid { 181 case 0: 182 t.ClearYAMAException() 183 return 0, nil, nil 184 case linux.PR_SET_PTRACER_ANY: 185 t.SetYAMAException(nil) 186 return 0, nil, nil 187 default: 188 tracer := t.PIDNamespace().TaskWithID(kernel.ThreadID(pid)) 189 if tracer == nil { 190 return 0, nil, linuxerr.EINVAL 191 } 192 t.SetYAMAException(tracer) 193 return 0, nil, nil 194 } 195 196 case linux.PR_SET_SECCOMP: 197 if args[1].Int() != linux.SECCOMP_MODE_FILTER { 198 // Unsupported mode. 199 return 0, nil, linuxerr.EINVAL 200 } 201 202 return 0, nil, seccomp(t, linux.SECCOMP_SET_MODE_FILTER, 0, args[2].Pointer()) 203 204 case linux.PR_GET_SECCOMP: 205 return uintptr(t.SeccompMode()), nil, nil 206 207 case linux.PR_CAPBSET_READ: 208 cp := linux.Capability(args[1].Uint64()) 209 if !cp.Ok() { 210 return 0, nil, linuxerr.EINVAL 211 } 212 var rv uintptr 213 if auth.CapabilitySetOf(cp)&t.Credentials().BoundingCaps != 0 { 214 rv = 1 215 } 216 return rv, nil, nil 217 218 case linux.PR_CAPBSET_DROP: 219 cp := linux.Capability(args[1].Uint64()) 220 if !cp.Ok() { 221 return 0, nil, linuxerr.EINVAL 222 } 223 return 0, nil, t.DropBoundingCapability(cp) 224 225 case linux.PR_SET_CHILD_SUBREAPER: 226 // "If arg2 is nonzero, set the "child subreaper" attribute of 227 // the calling process; if arg2 is zero, unset the attribute." 228 isSubreaper := args[1].Int() != 0 229 t.ThreadGroup().SetChildSubreaper(isSubreaper) 230 return 0, nil, nil 231 232 case linux.PR_GET_CHILD_SUBREAPER: 233 var isSubreaper int32 234 if t.ThreadGroup().IsChildSubreaper() { 235 isSubreaper = 1 236 } 237 _, err := primitive.CopyInt32Out(t, args[1].Pointer(), isSubreaper) 238 return 0, nil, err 239 240 case linux.PR_GET_TIMING, 241 linux.PR_SET_TIMING, 242 linux.PR_GET_TSC, 243 linux.PR_SET_TSC, 244 linux.PR_TASK_PERF_EVENTS_DISABLE, 245 linux.PR_TASK_PERF_EVENTS_ENABLE, 246 linux.PR_GET_TIMERSLACK, 247 linux.PR_SET_TIMERSLACK, 248 linux.PR_MCE_KILL, 249 linux.PR_MCE_KILL_GET, 250 linux.PR_GET_TID_ADDRESS, 251 linux.PR_GET_THP_DISABLE, 252 linux.PR_SET_THP_DISABLE, 253 linux.PR_MPX_ENABLE_MANAGEMENT, 254 linux.PR_MPX_DISABLE_MANAGEMENT: 255 256 t.Kernel().EmitUnimplementedEvent(t, sysno) 257 fallthrough 258 default: 259 return 0, nil, linuxerr.EINVAL 260 } 261 262 return 0, nil, nil 263 }