github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/sentry/syscalls/linux/sys_thread.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/ttpreport/gvisor-ligolo/pkg/abi/linux" 19 "github.com/ttpreport/gvisor-ligolo/pkg/errors/linuxerr" 20 "github.com/ttpreport/gvisor-ligolo/pkg/fspath" 21 "github.com/ttpreport/gvisor-ligolo/pkg/hostarch" 22 "github.com/ttpreport/gvisor-ligolo/pkg/marshal/primitive" 23 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/arch" 24 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel" 25 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel/sched" 26 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/loader" 27 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/seccheck" 28 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/vfs" 29 "github.com/ttpreport/gvisor-ligolo/pkg/usermem" 30 ) 31 32 var ( 33 // ExecMaxTotalSize is the maximum length of all argv and envv entries. 34 // 35 // N.B. The behavior here is different than Linux. Linux provides a limit on 36 // individual arguments of 32 pages, and an aggregate limit of at least 32 pages 37 // but otherwise bounded by min(stack size / 4, 8 MB * 3 / 4). We don't implement 38 // any behavior based on the stack size, and instead provide a fixed hard-limit of 39 // 2 MB (which should work well given that 8 MB stack limits are common). 40 ExecMaxTotalSize = 2 * 1024 * 1024 41 42 // ExecMaxElemSize is the maximum length of a single argv or envv entry. 43 ExecMaxElemSize = 32 * hostarch.PageSize 44 ) 45 46 // Getppid implements linux syscall getppid(2). 47 func Getppid(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 48 parent := t.Parent() 49 if parent == nil { 50 return 0, nil, nil 51 } 52 return uintptr(t.PIDNamespace().IDOfThreadGroup(parent.ThreadGroup())), nil, nil 53 } 54 55 // Getpid implements linux syscall getpid(2). 56 func Getpid(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 57 return uintptr(t.ThreadGroup().ID()), nil, nil 58 } 59 60 // Gettid implements linux syscall gettid(2). 61 func Gettid(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 62 return uintptr(t.ThreadID()), nil, nil 63 } 64 65 // Execve implements linux syscall execve(2). 66 func Execve(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 67 pathnameAddr := args[0].Pointer() 68 argvAddr := args[1].Pointer() 69 envvAddr := args[2].Pointer() 70 return execveat(t, linux.AT_FDCWD, pathnameAddr, argvAddr, envvAddr, 0 /* flags */) 71 } 72 73 // Execveat implements linux syscall execveat(2). 74 func Execveat(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 75 dirfd := args[0].Int() 76 pathnameAddr := args[1].Pointer() 77 argvAddr := args[2].Pointer() 78 envvAddr := args[3].Pointer() 79 flags := args[4].Int() 80 return execveat(t, dirfd, pathnameAddr, argvAddr, envvAddr, flags) 81 } 82 83 func execveat(t *kernel.Task, dirfd int32, pathnameAddr, argvAddr, envvAddr hostarch.Addr, flags int32) (uintptr, *kernel.SyscallControl, error) { 84 if flags&^(linux.AT_EMPTY_PATH|linux.AT_SYMLINK_NOFOLLOW) != 0 { 85 return 0, nil, linuxerr.EINVAL 86 } 87 88 pathname, err := t.CopyInString(pathnameAddr, linux.PATH_MAX) 89 if err != nil { 90 return 0, nil, err 91 } 92 var argv, envv []string 93 if argvAddr != 0 { 94 var err error 95 argv, err = t.CopyInVector(argvAddr, ExecMaxElemSize, ExecMaxTotalSize) 96 if err != nil { 97 return 0, nil, err 98 } 99 } 100 if envvAddr != 0 { 101 var err error 102 envv, err = t.CopyInVector(envvAddr, ExecMaxElemSize, ExecMaxTotalSize) 103 if err != nil { 104 return 0, nil, err 105 } 106 } 107 108 root := t.FSContext().RootDirectory() 109 defer root.DecRef(t) 110 var executable *vfs.FileDescription 111 defer func() { 112 if executable != nil { 113 executable.DecRef(t) 114 } 115 }() 116 closeOnExec := false 117 if path := fspath.Parse(pathname); dirfd != linux.AT_FDCWD && !path.Absolute { 118 // We must open the executable ourselves since dirfd is used as the 119 // starting point while resolving path, but the task working directory 120 // is used as the starting point while resolving interpreters (Linux: 121 // fs/binfmt_script.c:load_script() => fs/exec.c:open_exec() => 122 // do_open_execat(fd=AT_FDCWD)), and the loader package is currently 123 // incapable of handling this correctly. 124 if !path.HasComponents() && flags&linux.AT_EMPTY_PATH == 0 { 125 return 0, nil, linuxerr.ENOENT 126 } 127 dirfile, dirfileFlags := t.FDTable().Get(dirfd) 128 if dirfile == nil { 129 return 0, nil, linuxerr.EBADF 130 } 131 start := dirfile.VirtualDentry() 132 start.IncRef() 133 dirfile.DecRef(t) 134 closeOnExec = dirfileFlags.CloseOnExec 135 file, err := t.Kernel().VFS().OpenAt(t, t.Credentials(), &vfs.PathOperation{ 136 Root: root, 137 Start: start, 138 Path: path, 139 FollowFinalSymlink: flags&linux.AT_SYMLINK_NOFOLLOW == 0, 140 }, &vfs.OpenOptions{ 141 Flags: linux.O_RDONLY, 142 FileExec: true, 143 }) 144 start.DecRef(t) 145 if err != nil { 146 return 0, nil, err 147 } 148 executable = file 149 pathname = executable.MappedName(t) 150 } 151 152 // Load the new TaskImage. 153 wd := t.FSContext().WorkingDirectory() 154 defer wd.DecRef(t) 155 remainingTraversals := uint(linux.MaxSymlinkTraversals) 156 loadArgs := loader.LoadArgs{ 157 Root: root, 158 WorkingDir: wd, 159 RemainingTraversals: &remainingTraversals, 160 ResolveFinal: flags&linux.AT_SYMLINK_NOFOLLOW == 0, 161 Filename: pathname, 162 File: executable, 163 CloseOnExec: closeOnExec, 164 Argv: argv, 165 Envv: envv, 166 Features: t.Kernel().FeatureSet(), 167 } 168 if seccheck.Global.Enabled(seccheck.PointExecve) { 169 // Retain the first executable file that is opened (which may open 170 // multiple executable files while resolving interpreter scripts). 171 if executable == nil { 172 loadArgs.AfterOpen = func(f *vfs.FileDescription) { 173 if executable == nil { 174 f.IncRef() 175 executable = f 176 pathname = executable.MappedName(t) 177 } 178 } 179 } 180 } 181 182 image, se := t.Kernel().LoadTaskImage(t, loadArgs) 183 if se != nil { 184 return 0, nil, se.ToError() 185 } 186 187 ctrl, err := t.Execve(image, argv, envv, executable, pathname) 188 return 0, ctrl, err 189 } 190 191 // Exit implements linux syscall exit(2). 192 func Exit(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 193 status := args[0].Int() 194 t.PrepareExit(linux.WaitStatusExit(status & 0xff)) 195 return 0, kernel.CtrlDoExit, nil 196 } 197 198 // ExitGroup implements linux syscall exit_group(2). 199 func ExitGroup(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 200 status := args[0].Int() 201 t.PrepareGroupExit(linux.WaitStatusExit(status & 0xff)) 202 return 0, kernel.CtrlDoExit, nil 203 } 204 205 // clone is used by Clone, Fork, and VFork. 206 func clone(t *kernel.Task, flags int, stack hostarch.Addr, parentTID hostarch.Addr, childTID hostarch.Addr, tls hostarch.Addr) (uintptr, *kernel.SyscallControl, error) { 207 args := linux.CloneArgs{ 208 Flags: uint64(uint32(flags) &^ linux.CSIGNAL), 209 Pidfd: uint64(parentTID), 210 ChildTID: uint64(childTID), 211 ParentTID: uint64(parentTID), 212 ExitSignal: uint64(flags & linux.CSIGNAL), 213 Stack: uint64(stack), 214 TLS: uint64(tls), 215 } 216 ntid, ctrl, err := t.Clone(&args) 217 return uintptr(ntid), ctrl, err 218 } 219 220 // Fork implements Linux syscall fork(2). 221 func Fork(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 222 // "A call to fork() is equivalent to a call to clone(2) specifying flags 223 // as just SIGCHLD." - fork(2) 224 return clone(t, int(linux.SIGCHLD), 0, 0, 0, 0) 225 } 226 227 // Vfork implements Linux syscall vfork(2). 228 func Vfork(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 229 // """ 230 // A call to vfork() is equivalent to calling clone(2) with flags specified as: 231 // 232 // CLONE_VM | CLONE_VFORK | SIGCHLD 233 // """ - vfork(2) 234 return clone(t, linux.CLONE_VM|linux.CLONE_VFORK|int(linux.SIGCHLD), 0, 0, 0, 0) 235 } 236 237 // parseCommonWaitOptions applies the options common to wait4 and waitid to 238 // wopts. 239 func parseCommonWaitOptions(wopts *kernel.WaitOptions, options int) error { 240 switch options & (linux.WCLONE | linux.WALL) { 241 case 0: 242 wopts.NonCloneTasks = true 243 case linux.WCLONE: 244 wopts.CloneTasks = true 245 case linux.WALL: 246 wopts.NonCloneTasks = true 247 wopts.CloneTasks = true 248 default: 249 return linuxerr.EINVAL 250 } 251 if options&linux.WCONTINUED != 0 { 252 wopts.Events |= kernel.EventGroupContinue 253 } 254 if options&linux.WNOHANG == 0 { 255 wopts.BlockInterruptErr = linuxerr.ERESTARTSYS 256 } 257 if options&linux.WNOTHREAD == 0 { 258 wopts.SiblingChildren = true 259 } 260 return nil 261 } 262 263 // wait4 waits for the given child process to exit. 264 func wait4(t *kernel.Task, pid int, statusAddr hostarch.Addr, options int, rusageAddr hostarch.Addr) (uintptr, error) { 265 if options&^(linux.WNOHANG|linux.WUNTRACED|linux.WCONTINUED|linux.WNOTHREAD|linux.WALL|linux.WCLONE) != 0 { 266 return 0, linuxerr.EINVAL 267 } 268 wopts := kernel.WaitOptions{ 269 Events: kernel.EventExit | kernel.EventTraceeStop, 270 ConsumeEvent: true, 271 } 272 // There are four cases to consider: 273 // 274 // pid < -1 any child process whose process group ID is equal to the absolute value of pid 275 // pid == -1 any child process 276 // pid == 0 any child process whose process group ID is equal to that of the calling process 277 // pid > 0 the child whose process ID is equal to the value of pid 278 switch { 279 case pid < -1: 280 wopts.SpecificPGID = kernel.ProcessGroupID(-pid) 281 case pid == -1: 282 // Any process is the default. 283 case pid == 0: 284 wopts.SpecificPGID = t.PIDNamespace().IDOfProcessGroup(t.ThreadGroup().ProcessGroup()) 285 default: 286 wopts.SpecificTID = kernel.ThreadID(pid) 287 } 288 289 if err := parseCommonWaitOptions(&wopts, options); err != nil { 290 return 0, err 291 } 292 if options&linux.WUNTRACED != 0 { 293 wopts.Events |= kernel.EventChildGroupStop 294 } 295 296 wr, err := t.Wait(&wopts) 297 if err != nil { 298 if err == kernel.ErrNoWaitableEvent { 299 return 0, nil 300 } 301 return 0, err 302 } 303 if statusAddr != 0 { 304 if _, err := primitive.CopyUint32Out(t, statusAddr, uint32(wr.Status)); err != nil { 305 return 0, err 306 } 307 } 308 if rusageAddr != 0 { 309 ru := getrusage(wr.Task, linux.RUSAGE_BOTH) 310 if _, err := ru.CopyOut(t, rusageAddr); err != nil { 311 return 0, err 312 } 313 } 314 return uintptr(wr.TID), nil 315 } 316 317 // Wait4 implements linux syscall wait4(2). 318 func Wait4(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 319 pid := int(args[0].Int()) 320 statusAddr := args[1].Pointer() 321 options := int(args[2].Uint()) 322 rusageAddr := args[3].Pointer() 323 324 n, err := wait4(t, pid, statusAddr, options, rusageAddr) 325 return n, nil, err 326 } 327 328 // WaitPid implements linux syscall waitpid(2). 329 func WaitPid(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 330 pid := int(args[0].Int()) 331 statusAddr := args[1].Pointer() 332 options := int(args[2].Uint()) 333 334 n, err := wait4(t, pid, statusAddr, options, 0) 335 return n, nil, err 336 } 337 338 // Waitid implements linux syscall waitid(2). 339 func Waitid(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 340 idtype := args[0].Int() 341 id := args[1].Int() 342 infop := args[2].Pointer() 343 options := int(args[3].Uint()) 344 rusageAddr := args[4].Pointer() 345 346 if options&^(linux.WNOHANG|linux.WEXITED|linux.WSTOPPED|linux.WCONTINUED|linux.WNOWAIT|linux.WNOTHREAD|linux.WALL|linux.WCLONE) != 0 { 347 return 0, nil, linuxerr.EINVAL 348 } 349 if options&(linux.WEXITED|linux.WSTOPPED|linux.WCONTINUED) == 0 { 350 return 0, nil, linuxerr.EINVAL 351 } 352 wopts := kernel.WaitOptions{ 353 Events: kernel.EventTraceeStop, 354 ConsumeEvent: options&linux.WNOWAIT == 0, 355 } 356 switch idtype { 357 case linux.P_ALL: 358 case linux.P_PID: 359 wopts.SpecificTID = kernel.ThreadID(id) 360 case linux.P_PGID: 361 wopts.SpecificPGID = kernel.ProcessGroupID(id) 362 default: 363 return 0, nil, linuxerr.EINVAL 364 } 365 366 if err := parseCommonWaitOptions(&wopts, options); err != nil { 367 return 0, nil, err 368 } 369 if options&linux.WEXITED != 0 { 370 wopts.Events |= kernel.EventExit 371 } 372 if options&linux.WSTOPPED != 0 { 373 wopts.Events |= kernel.EventChildGroupStop 374 } 375 376 wr, err := t.Wait(&wopts) 377 if err != nil { 378 if err == kernel.ErrNoWaitableEvent { 379 err = nil 380 // "If WNOHANG was specified in options and there were no children 381 // in a waitable state, then waitid() returns 0 immediately and the 382 // state of the siginfo_t structure pointed to by infop is 383 // unspecified." - waitid(2). But Linux's waitid actually zeroes 384 // out the fields it would set for a successful waitid in this case 385 // as well. 386 if infop != 0 { 387 var si linux.SignalInfo 388 _, err = si.CopyOut(t, infop) 389 } 390 } 391 return 0, nil, err 392 } 393 if rusageAddr != 0 { 394 ru := getrusage(wr.Task, linux.RUSAGE_BOTH) 395 if _, err := ru.CopyOut(t, rusageAddr); err != nil { 396 return 0, nil, err 397 } 398 } 399 if infop == 0 { 400 return 0, nil, nil 401 } 402 si := linux.SignalInfo{ 403 Signo: int32(linux.SIGCHLD), 404 } 405 si.SetPID(int32(wr.TID)) 406 si.SetUID(int32(wr.UID)) 407 s := wr.Status 408 switch { 409 case s.Exited(): 410 si.Code = linux.CLD_EXITED 411 si.SetStatus(int32(s.ExitStatus())) 412 case s.Signaled(): 413 if s.CoreDumped() { 414 si.Code = linux.CLD_DUMPED 415 } else { 416 si.Code = linux.CLD_KILLED 417 } 418 si.SetStatus(int32(s.TerminationSignal())) 419 case s.Stopped(): 420 if wr.Event == kernel.EventTraceeStop { 421 si.Code = linux.CLD_TRAPPED 422 si.SetStatus(int32(s.PtraceEvent())) 423 } else { 424 si.Code = linux.CLD_STOPPED 425 si.SetStatus(int32(s.StopSignal())) 426 } 427 case s.Continued(): 428 si.Code = linux.CLD_CONTINUED 429 si.SetStatus(int32(linux.SIGCONT)) 430 default: 431 t.Warningf("waitid got incomprehensible wait status %d", s) 432 } 433 _, err = si.CopyOut(t, infop) 434 return 0, nil, err 435 } 436 437 // SetTidAddress implements linux syscall set_tid_address(2). 438 func SetTidAddress(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 439 addr := args[0].Pointer() 440 441 // Always succeed, return caller's tid. 442 t.SetClearTID(addr) 443 return uintptr(t.ThreadID()), nil, nil 444 } 445 446 // Setns implements linux syscall setns(2). 447 func Setns(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 448 fd := args[0].Int() 449 450 file := t.GetFile(fd) 451 if file == nil { 452 return 0, nil, linuxerr.EBADF 453 } 454 defer file.DecRef(t) 455 456 flags := args[1].Int() 457 return 0, nil, t.Setns(file, flags) 458 } 459 460 // Unshare implements linux syscall unshare(2). 461 func Unshare(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 462 flags := args[0].Int() 463 // "CLONE_NEWPID automatically implies CLONE_THREAD as well." - unshare(2) 464 if flags&linux.CLONE_NEWPID != 0 { 465 flags |= linux.CLONE_THREAD 466 } 467 // "... specifying CLONE_NEWUSER automatically implies CLONE_THREAD. Since 468 // Linux 3.9, CLONE_NEWUSER also automatically implies CLONE_FS." 469 if flags&linux.CLONE_NEWUSER != 0 { 470 flags |= linux.CLONE_THREAD | linux.CLONE_FS 471 } 472 return 0, nil, t.Unshare(flags) 473 } 474 475 // SchedYield implements linux syscall sched_yield(2). 476 func SchedYield(t *kernel.Task, sysno uintptr, _ arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 477 t.Yield() 478 return 0, nil, nil 479 } 480 481 // SchedSetaffinity implements linux syscall sched_setaffinity(2). 482 func SchedSetaffinity(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 483 tid := args[0].Int() 484 size := args[1].SizeT() 485 maskAddr := args[2].Pointer() 486 487 var task *kernel.Task 488 if tid == 0 { 489 task = t 490 } else { 491 task = t.PIDNamespace().TaskWithID(kernel.ThreadID(tid)) 492 if task == nil { 493 return 0, nil, linuxerr.ESRCH 494 } 495 } 496 497 mask := sched.NewCPUSet(t.Kernel().ApplicationCores()) 498 if size > mask.Size() { 499 size = mask.Size() 500 } 501 if _, err := t.CopyInBytes(maskAddr, mask[:size]); err != nil { 502 return 0, nil, err 503 } 504 return 0, nil, task.SetCPUMask(mask) 505 } 506 507 // SchedGetaffinity implements linux syscall sched_getaffinity(2). 508 func SchedGetaffinity(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 509 tid := args[0].Int() 510 size := args[1].SizeT() 511 maskAddr := args[2].Pointer() 512 513 // This limitation is because linux stores the cpumask 514 // in an array of "unsigned long" so the buffer needs to 515 // be a multiple of the word size. 516 if size&(t.Arch().Width()-1) > 0 { 517 return 0, nil, linuxerr.EINVAL 518 } 519 520 var task *kernel.Task 521 if tid == 0 { 522 task = t 523 } else { 524 task = t.PIDNamespace().TaskWithID(kernel.ThreadID(tid)) 525 if task == nil { 526 return 0, nil, linuxerr.ESRCH 527 } 528 } 529 530 mask := task.CPUMask() 531 // The buffer needs to be big enough to hold a cpumask with 532 // all possible cpus. 533 if size < mask.Size() { 534 return 0, nil, linuxerr.EINVAL 535 } 536 _, err := t.CopyOutBytes(maskAddr, mask) 537 538 // NOTE: The syscall interface is slightly different than the glibc 539 // interface. The raw sched_getaffinity syscall returns the number of 540 // bytes used to represent a cpu mask. 541 return uintptr(mask.Size()), nil, err 542 } 543 544 // Getcpu implements linux syscall getcpu(2). 545 func Getcpu(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 546 cpu := args[0].Pointer() 547 node := args[1].Pointer() 548 // third argument to this system call is nowadays unused. 549 550 if cpu != 0 { 551 if _, err := primitive.CopyInt32Out(t, cpu, t.CPU()); err != nil { 552 return 0, nil, err 553 } 554 } 555 // We always return node 0. 556 if node != 0 { 557 if _, err := t.MemoryManager().ZeroOut(t, node, 4, usermem.IOOpts{ 558 AddressSpaceActive: true, 559 }); err != nil { 560 return 0, nil, err 561 } 562 } 563 return 0, nil, nil 564 } 565 566 // Setpgid implements the linux syscall setpgid(2). 567 func Setpgid(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 568 // Note that throughout this function, pgid is interpreted with respect 569 // to t's namespace, not with respect to the selected ThreadGroup's 570 // namespace (which may be different). 571 pid := kernel.ThreadID(args[0].Int()) 572 pgid := kernel.ProcessGroupID(args[1].Int()) 573 574 // "If pid is zero, then the process ID of the calling process is used." 575 tg := t.ThreadGroup() 576 if pid != 0 { 577 ot := t.PIDNamespace().TaskWithID(pid) 578 if ot == nil { 579 return 0, nil, linuxerr.ESRCH 580 } 581 tg = ot.ThreadGroup() 582 if tg.Leader() != ot { 583 return 0, nil, linuxerr.EINVAL 584 } 585 586 // Setpgid only operates on child threadgroups. 587 if tg != t.ThreadGroup() && (tg.Leader().Parent() == nil || tg.Leader().Parent().ThreadGroup() != t.ThreadGroup()) { 588 return 0, nil, linuxerr.ESRCH 589 } 590 } 591 592 // "If pgid is zero, then the PGID of the process specified by pid is made 593 // the same as its process ID." 594 defaultPGID := kernel.ProcessGroupID(t.PIDNamespace().IDOfThreadGroup(tg)) 595 if pgid == 0 { 596 pgid = defaultPGID 597 } else if pgid < 0 { 598 return 0, nil, linuxerr.EINVAL 599 } 600 601 // If the pgid is the same as the group, then create a new one. Otherwise, 602 // we attempt to join an existing process group. 603 if pgid == defaultPGID { 604 // For convenience, errors line up with Linux syscall API. 605 if err := tg.CreateProcessGroup(); err != nil { 606 // Is the process group already as expected? If so, 607 // just return success. This is the same behavior as 608 // Linux. 609 if t.PIDNamespace().IDOfProcessGroup(tg.ProcessGroup()) == defaultPGID { 610 return 0, nil, nil 611 } 612 return 0, nil, err 613 } 614 } else { 615 // Same as CreateProcessGroup, above. 616 if err := tg.JoinProcessGroup(t.PIDNamespace(), pgid, tg != t.ThreadGroup()); err != nil { 617 // See above. 618 if t.PIDNamespace().IDOfProcessGroup(tg.ProcessGroup()) == pgid { 619 return 0, nil, nil 620 } 621 return 0, nil, err 622 } 623 } 624 625 // Success. 626 return 0, nil, nil 627 } 628 629 // Getpgrp implements the linux syscall getpgrp(2). 630 func Getpgrp(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 631 return uintptr(t.PIDNamespace().IDOfProcessGroup(t.ThreadGroup().ProcessGroup())), nil, nil 632 } 633 634 // Getpgid implements the linux syscall getpgid(2). 635 func Getpgid(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 636 tid := kernel.ThreadID(args[0].Int()) 637 if tid == 0 { 638 return Getpgrp(t, sysno, args) 639 } 640 641 target := t.PIDNamespace().TaskWithID(tid) 642 if target == nil { 643 return 0, nil, linuxerr.ESRCH 644 } 645 646 return uintptr(t.PIDNamespace().IDOfProcessGroup(target.ThreadGroup().ProcessGroup())), nil, nil 647 } 648 649 // Setsid implements the linux syscall setsid(2). 650 func Setsid(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 651 return 0, nil, t.ThreadGroup().CreateSession() 652 } 653 654 // Getsid implements the linux syscall getsid(2). 655 func Getsid(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 656 tid := kernel.ThreadID(args[0].Int()) 657 if tid == 0 { 658 return uintptr(t.PIDNamespace().IDOfSession(t.ThreadGroup().Session())), nil, nil 659 } 660 661 target := t.PIDNamespace().TaskWithID(tid) 662 if target == nil { 663 return 0, nil, linuxerr.ESRCH 664 } 665 666 return uintptr(t.PIDNamespace().IDOfSession(target.ThreadGroup().Session())), nil, nil 667 } 668 669 // Getpriority pretends to implement the linux syscall getpriority(2). 670 // 671 // This is a stub; real priorities require a full scheduler. 672 func Getpriority(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 673 which := args[0].Int() 674 who := kernel.ThreadID(args[1].Int()) 675 676 switch which { 677 case linux.PRIO_PROCESS: 678 // Look for who, return ESRCH if not found. 679 var task *kernel.Task 680 if who == 0 { 681 task = t 682 } else { 683 task = t.PIDNamespace().TaskWithID(who) 684 } 685 686 if task == nil { 687 return 0, nil, linuxerr.ESRCH 688 } 689 690 // From kernel/sys.c:getpriority: 691 // "To avoid negative return values, 'getpriority()' 692 // will not return the normal nice-value, but a negated 693 // value that has been offset by 20" 694 return uintptr(20 - task.Niceness()), nil, nil 695 case linux.PRIO_USER: 696 fallthrough 697 case linux.PRIO_PGRP: 698 // PRIO_USER and PRIO_PGRP have no further implementation yet. 699 return 0, nil, nil 700 default: 701 return 0, nil, linuxerr.EINVAL 702 } 703 } 704 705 // Setpriority pretends to implement the linux syscall setpriority(2). 706 // 707 // This is a stub; real priorities require a full scheduler. 708 func Setpriority(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 709 which := args[0].Int() 710 who := kernel.ThreadID(args[1].Int()) 711 niceval := int(args[2].Int()) 712 713 // In the kernel's implementation, values outside the range 714 // of [-20, 19] are truncated to these minimum and maximum 715 // values. 716 if niceval < -20 /* min niceval */ { 717 niceval = -20 718 } else if niceval > 19 /* max niceval */ { 719 niceval = 19 720 } 721 722 switch which { 723 case linux.PRIO_PROCESS: 724 // Look for who, return ESRCH if not found. 725 var task *kernel.Task 726 if who == 0 { 727 task = t 728 } else { 729 task = t.PIDNamespace().TaskWithID(who) 730 } 731 732 if task == nil { 733 return 0, nil, linuxerr.ESRCH 734 } 735 736 task.SetNiceness(niceval) 737 case linux.PRIO_USER: 738 fallthrough 739 case linux.PRIO_PGRP: 740 // PRIO_USER and PRIO_PGRP have no further implementation yet. 741 return 0, nil, nil 742 default: 743 return 0, nil, linuxerr.EINVAL 744 } 745 746 return 0, nil, nil 747 } 748 749 // Ptrace implements linux system call ptrace(2). 750 func Ptrace(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 751 req := args[0].Int64() 752 pid := kernel.ThreadID(args[1].Int()) 753 addr := args[2].Pointer() 754 data := args[3].Pointer() 755 756 return 0, nil, t.Ptrace(req, pid, addr, data) 757 }