github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/syscalls/linux/sys_signal.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 "math" 19 "time" 20 21 "github.com/nicocha30/gvisor-ligolo/pkg/abi/linux" 22 "github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr" 23 "github.com/nicocha30/gvisor-ligolo/pkg/hostarch" 24 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch" 25 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/fsimpl/signalfd" 26 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel" 27 ) 28 29 // "For a process to have permission to send a signal it must 30 // - either be privileged (CAP_KILL), or 31 // - the real or effective user ID of the sending process must be equal to the 32 // 33 // real or saved set-user-ID of the target process. 34 // 35 // In the case of SIGCONT it suffices when the sending and receiving processes 36 // belong to the same session." - kill(2) 37 // 38 // Equivalent to kernel/signal.c:check_kill_permission. 39 func mayKill(t *kernel.Task, target *kernel.Task, sig linux.Signal) bool { 40 // kernel/signal.c:check_kill_permission also allows a signal if the 41 // sending and receiving tasks share a thread group, which is not 42 // mentioned in kill(2) since kill does not allow task-level 43 // granularity in signal sending. 44 if t.ThreadGroup() == target.ThreadGroup() { 45 return true 46 } 47 48 if t.HasCapabilityIn(linux.CAP_KILL, target.UserNamespace()) { 49 return true 50 } 51 52 creds := t.Credentials() 53 tcreds := target.Credentials() 54 if creds.EffectiveKUID == tcreds.SavedKUID || 55 creds.EffectiveKUID == tcreds.RealKUID || 56 creds.RealKUID == tcreds.SavedKUID || 57 creds.RealKUID == tcreds.RealKUID { 58 return true 59 } 60 61 if sig == linux.SIGCONT && target.ThreadGroup().Session() == t.ThreadGroup().Session() { 62 return true 63 } 64 return false 65 } 66 67 // Kill implements linux syscall kill(2). 68 func Kill(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 69 pid := kernel.ThreadID(args[0].Int()) 70 sig := linux.Signal(args[1].Int()) 71 72 switch { 73 case pid > 0: 74 // "If pid is positive, then signal sig is sent to the process with the 75 // ID specified by pid." - kill(2) 76 // This loops to handle races with execve where target dies between 77 // TaskWithID and SendGroupSignal. Compare Linux's 78 // kernel/signal.c:kill_pid_info(). 79 for { 80 target := t.PIDNamespace().TaskWithID(pid) 81 if target == nil { 82 return 0, nil, linuxerr.ESRCH 83 } 84 if !mayKill(t, target, sig) { 85 return 0, nil, linuxerr.EPERM 86 } 87 info := &linux.SignalInfo{ 88 Signo: int32(sig), 89 Code: linux.SI_USER, 90 } 91 info.SetPID(int32(target.PIDNamespace().IDOfTask(t))) 92 info.SetUID(int32(t.Credentials().RealKUID.In(target.UserNamespace()).OrOverflow())) 93 if err := target.SendGroupSignal(info); !linuxerr.Equals(linuxerr.ESRCH, err) { 94 return 0, nil, err 95 } 96 } 97 case pid == -1: 98 // "If pid equals -1, then sig is sent to every process for which the 99 // calling process has permission to send signals, except for process 1 100 // (init), but see below. ... POSIX.1-2001 requires that kill(-1,sig) 101 // send sig to all processes that the calling process may send signals 102 // to, except possibly for some implementation-defined system 103 // processes. Linux allows a process to signal itself, but on Linux the 104 // call kill(-1,sig) does not signal the calling process." 105 var ( 106 lastErr error 107 delivered int 108 ) 109 for _, tg := range t.PIDNamespace().ThreadGroups() { 110 if tg == t.ThreadGroup() { 111 continue 112 } 113 // Don't send the signal to the init process in t's PID namespace. 114 if tg.IsInitIn(t.PIDNamespace()) { 115 continue 116 } 117 118 // If pid == -1, the returned error is the last non-EPERM error 119 // from any call to group_send_sig_info. 120 if !mayKill(t, tg.Leader(), sig) { 121 continue 122 } 123 // Here and below, whether or not kill returns an error may 124 // depend on the iteration order. We at least implement the 125 // semantics documented by the man page: "On success (at least 126 // one signal was sent), zero is returned." 127 info := &linux.SignalInfo{ 128 Signo: int32(sig), 129 Code: linux.SI_USER, 130 } 131 info.SetPID(int32(tg.PIDNamespace().IDOfTask(t))) 132 info.SetUID(int32(t.Credentials().RealKUID.In(tg.Leader().UserNamespace()).OrOverflow())) 133 err := tg.SendSignal(info) 134 if linuxerr.Equals(linuxerr.ESRCH, err) { 135 // ESRCH is ignored because it means the task 136 // exited while we were iterating. This is a 137 // race which would not normally exist on 138 // Linux, so we suppress it. 139 continue 140 } 141 delivered++ 142 if err != nil { 143 lastErr = err 144 } 145 } 146 if delivered > 0 { 147 return 0, nil, lastErr 148 } 149 return 0, nil, linuxerr.ESRCH 150 default: 151 // "If pid equals 0, then sig is sent to every process in the process 152 // group of the calling process." 153 // 154 // "If pid is less than -1, then sig is sent to every process 155 // in the process group whose ID is -pid." 156 pgid := kernel.ProcessGroupID(-pid) 157 if pgid == 0 { 158 pgid = t.PIDNamespace().IDOfProcessGroup(t.ThreadGroup().ProcessGroup()) 159 } 160 161 // If pid != -1 (i.e. signalling a process group), the returned error 162 // is the last error from any call to group_send_sig_info. 163 lastErr := error(linuxerr.ESRCH) 164 for _, tg := range t.PIDNamespace().ThreadGroups() { 165 if t.PIDNamespace().IDOfProcessGroup(tg.ProcessGroup()) == pgid { 166 if !mayKill(t, tg.Leader(), sig) { 167 lastErr = linuxerr.EPERM 168 continue 169 } 170 171 info := &linux.SignalInfo{ 172 Signo: int32(sig), 173 Code: linux.SI_USER, 174 } 175 info.SetPID(int32(tg.PIDNamespace().IDOfTask(t))) 176 info.SetUID(int32(t.Credentials().RealKUID.In(tg.Leader().UserNamespace()).OrOverflow())) 177 // See note above regarding ESRCH race above. 178 if err := tg.SendSignal(info); !linuxerr.Equals(linuxerr.ESRCH, err) { 179 lastErr = err 180 } 181 } 182 } 183 184 return 0, nil, lastErr 185 } 186 } 187 188 func tkillSigInfo(sender, receiver *kernel.Task, sig linux.Signal) *linux.SignalInfo { 189 info := &linux.SignalInfo{ 190 Signo: int32(sig), 191 Code: linux.SI_TKILL, 192 } 193 info.SetPID(int32(receiver.PIDNamespace().IDOfThreadGroup(sender.ThreadGroup()))) 194 info.SetUID(int32(sender.Credentials().RealKUID.In(receiver.UserNamespace()).OrOverflow())) 195 return info 196 } 197 198 // Tkill implements linux syscall tkill(2). 199 func Tkill(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 200 tid := kernel.ThreadID(args[0].Int()) 201 sig := linux.Signal(args[1].Int()) 202 203 // N.B. Inconsistent with man page, linux actually rejects calls with 204 // tid <=0 by EINVAL. This isn't the same for all signal calls. 205 if tid <= 0 { 206 return 0, nil, linuxerr.EINVAL 207 } 208 209 target := t.PIDNamespace().TaskWithID(tid) 210 if target == nil { 211 return 0, nil, linuxerr.ESRCH 212 } 213 214 if !mayKill(t, target, sig) { 215 return 0, nil, linuxerr.EPERM 216 } 217 return 0, nil, target.SendSignal(tkillSigInfo(t, target, sig)) 218 } 219 220 // Tgkill implements linux syscall tgkill(2). 221 func Tgkill(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 222 tgid := kernel.ThreadID(args[0].Int()) 223 tid := kernel.ThreadID(args[1].Int()) 224 sig := linux.Signal(args[2].Int()) 225 226 // N.B. Inconsistent with man page, linux actually rejects calls with 227 // tgid/tid <=0 by EINVAL. This isn't the same for all signal calls. 228 if tgid <= 0 || tid <= 0 { 229 return 0, nil, linuxerr.EINVAL 230 } 231 232 targetTG := t.PIDNamespace().ThreadGroupWithID(tgid) 233 target := t.PIDNamespace().TaskWithID(tid) 234 if targetTG == nil || target == nil || target.ThreadGroup() != targetTG { 235 return 0, nil, linuxerr.ESRCH 236 } 237 238 if !mayKill(t, target, sig) { 239 return 0, nil, linuxerr.EPERM 240 } 241 return 0, nil, target.SendSignal(tkillSigInfo(t, target, sig)) 242 } 243 244 // RtSigaction implements linux syscall rt_sigaction(2). 245 func RtSigaction(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 246 sig := linux.Signal(args[0].Int()) 247 newactarg := args[1].Pointer() 248 oldactarg := args[2].Pointer() 249 sigsetsize := args[3].SizeT() 250 251 if sigsetsize != linux.SignalSetSize { 252 return 0, nil, linuxerr.EINVAL 253 } 254 255 var newactptr *linux.SigAction 256 if newactarg != 0 { 257 var newact linux.SigAction 258 if _, err := newact.CopyIn(t, newactarg); err != nil { 259 return 0, nil, err 260 } 261 newactptr = &newact 262 } 263 oldact, err := t.ThreadGroup().SetSigAction(sig, newactptr) 264 if err != nil { 265 return 0, nil, err 266 } 267 if oldactarg != 0 { 268 if _, err := oldact.CopyOut(t, oldactarg); err != nil { 269 return 0, nil, err 270 } 271 } 272 return 0, nil, nil 273 } 274 275 // Sigreturn implements linux syscall sigreturn(2). 276 func Sigreturn(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 277 ctrl, err := t.SignalReturn(false) 278 return 0, ctrl, err 279 } 280 281 // RtSigreturn implements linux syscall rt_sigreturn(2). 282 func RtSigreturn(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 283 ctrl, err := t.SignalReturn(true) 284 return 0, ctrl, err 285 } 286 287 // RtSigprocmask implements linux syscall rt_sigprocmask(2). 288 func RtSigprocmask(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 289 how := args[0].Int() 290 setaddr := args[1].Pointer() 291 oldaddr := args[2].Pointer() 292 sigsetsize := args[3].SizeT() 293 294 if sigsetsize != linux.SignalSetSize { 295 return 0, nil, linuxerr.EINVAL 296 } 297 oldmask := t.SignalMask() 298 if setaddr != 0 { 299 mask, err := copyInSigSet(t, setaddr, sigsetsize) 300 if err != nil { 301 return 0, nil, err 302 } 303 304 switch how { 305 case linux.SIG_BLOCK: 306 t.SetSignalMask(oldmask | mask) 307 case linux.SIG_UNBLOCK: 308 t.SetSignalMask(oldmask &^ mask) 309 case linux.SIG_SETMASK: 310 t.SetSignalMask(mask) 311 default: 312 return 0, nil, linuxerr.EINVAL 313 } 314 } 315 if oldaddr != 0 { 316 return 0, nil, copyOutSigSet(t, oldaddr, oldmask) 317 } 318 319 return 0, nil, nil 320 } 321 322 // Sigaltstack implements linux syscall sigaltstack(2). 323 func Sigaltstack(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 324 setaddr := args[0].Pointer() 325 oldaddr := args[1].Pointer() 326 327 ctrl, err := t.SigaltStack(setaddr, oldaddr) 328 return 0, ctrl, err 329 } 330 331 // Pause implements linux syscall pause(2). 332 func Pause(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 333 return 0, nil, linuxerr.ConvertIntr(t.Block(nil), linuxerr.ERESTARTNOHAND) 334 } 335 336 // RtSigpending implements linux syscall rt_sigpending(2). 337 func RtSigpending(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 338 addr := args[0].Pointer() 339 pending := t.PendingSignals() 340 _, err := pending.CopyOut(t, addr) 341 return 0, nil, err 342 } 343 344 // RtSigtimedwait implements linux syscall rt_sigtimedwait(2). 345 func RtSigtimedwait(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 346 sigset := args[0].Pointer() 347 siginfo := args[1].Pointer() 348 timespec := args[2].Pointer() 349 sigsetsize := args[3].SizeT() 350 351 mask, err := copyInSigSet(t, sigset, sigsetsize) 352 if err != nil { 353 return 0, nil, err 354 } 355 356 var timeout time.Duration 357 if timespec != 0 { 358 d, err := copyTimespecIn(t, timespec) 359 if err != nil { 360 return 0, nil, err 361 } 362 if !d.Valid() { 363 return 0, nil, linuxerr.EINVAL 364 } 365 timeout = time.Duration(d.ToNsecCapped()) 366 } else { 367 timeout = time.Duration(math.MaxInt64) 368 } 369 370 si, err := t.Sigtimedwait(mask, timeout) 371 if err != nil { 372 return 0, nil, err 373 } 374 375 if siginfo != 0 { 376 si.FixSignalCodeForUser() 377 if _, err := si.CopyOut(t, siginfo); err != nil { 378 return 0, nil, err 379 } 380 } 381 return uintptr(si.Signo), nil, nil 382 } 383 384 // RtSigqueueinfo implements linux syscall rt_sigqueueinfo(2). 385 func RtSigqueueinfo(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 386 pid := kernel.ThreadID(args[0].Int()) 387 sig := linux.Signal(args[1].Int()) 388 infoAddr := args[2].Pointer() 389 390 // Copy in the info. 391 // 392 // We must ensure that the Signo is set (Linux overrides this in the 393 // same way), and that the code is in the allowed set. This same logic 394 // appears below in RtSigtgqueueinfo and should be kept in sync. 395 var info linux.SignalInfo 396 if _, err := info.CopyIn(t, infoAddr); err != nil { 397 return 0, nil, err 398 } 399 info.Signo = int32(sig) 400 401 // This must loop to handle the race with execve described in Kill. 402 for { 403 // Deliver to the given task's thread group. 404 target := t.PIDNamespace().TaskWithID(pid) 405 if target == nil { 406 return 0, nil, linuxerr.ESRCH 407 } 408 409 // If the sender is not the receiver, it can't use si_codes used by the 410 // kernel or SI_TKILL. 411 if (info.Code >= 0 || info.Code == linux.SI_TKILL) && target != t { 412 return 0, nil, linuxerr.EPERM 413 } 414 415 if !mayKill(t, target, sig) { 416 return 0, nil, linuxerr.EPERM 417 } 418 419 if err := target.SendGroupSignal(&info); !linuxerr.Equals(linuxerr.ESRCH, err) { 420 return 0, nil, err 421 } 422 } 423 } 424 425 // RtTgsigqueueinfo implements linux syscall rt_tgsigqueueinfo(2). 426 func RtTgsigqueueinfo(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 427 tgid := kernel.ThreadID(args[0].Int()) 428 tid := kernel.ThreadID(args[1].Int()) 429 sig := linux.Signal(args[2].Int()) 430 infoAddr := args[3].Pointer() 431 432 // N.B. Inconsistent with man page, linux actually rejects calls with 433 // tgid/tid <=0 by EINVAL. This isn't the same for all signal calls. 434 if tgid <= 0 || tid <= 0 { 435 return 0, nil, linuxerr.EINVAL 436 } 437 438 // Copy in the info. See RtSigqueueinfo above. 439 var info linux.SignalInfo 440 if _, err := info.CopyIn(t, infoAddr); err != nil { 441 return 0, nil, err 442 } 443 info.Signo = int32(sig) 444 445 // Deliver to the given task. 446 targetTG := t.PIDNamespace().ThreadGroupWithID(tgid) 447 target := t.PIDNamespace().TaskWithID(tid) 448 if targetTG == nil || target == nil || target.ThreadGroup() != targetTG { 449 return 0, nil, linuxerr.ESRCH 450 } 451 452 // If the sender is not the receiver, it can't use si_codes used by the 453 // kernel or SI_TKILL. 454 if (info.Code >= 0 || info.Code == linux.SI_TKILL) && target != t { 455 return 0, nil, linuxerr.EPERM 456 } 457 458 if !mayKill(t, target, sig) { 459 return 0, nil, linuxerr.EPERM 460 } 461 return 0, nil, target.SendSignal(&info) 462 } 463 464 // RtSigsuspend implements linux syscall rt_sigsuspend(2). 465 func RtSigsuspend(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 466 sigset := args[0].Pointer() 467 468 // Copy in the signal mask. 469 var mask linux.SignalSet 470 if _, err := mask.CopyIn(t, sigset); err != nil { 471 return 0, nil, err 472 } 473 mask &^= kernel.UnblockableSignals 474 475 // Swap the mask. 476 oldmask := t.SignalMask() 477 t.SetSignalMask(mask) 478 t.SetSavedSignalMask(oldmask) 479 480 // Perform the wait. 481 return 0, nil, linuxerr.ConvertIntr(t.Block(nil), linuxerr.ERESTARTNOHAND) 482 } 483 484 // RestartSyscall implements the linux syscall restart_syscall(2). 485 func RestartSyscall(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 486 if r := t.SyscallRestartBlock(); r != nil { 487 n, err := r.Restart(t) 488 return n, nil, err 489 } 490 // The restart block should never be nil here, but it's possible 491 // ERESTART_RESTARTBLOCK was set by ptrace without the current syscall 492 // setting up a restart block. If ptrace didn't manipulate the return value, 493 // finding a nil restart block is a bug. Linux ensures that the restart 494 // function is never null by (re)initializing it with one that translates 495 // the restart into EINTR. We'll emulate that behaviour. 496 t.Debugf("Restart block missing in restart_syscall(2). Did ptrace inject a return value of ERESTART_RESTARTBLOCK?") 497 return 0, nil, linuxerr.EINTR 498 } 499 500 // sharedSignalfd is shared between the two calls. 501 func sharedSignalfd(t *kernel.Task, fd int32, sigset hostarch.Addr, sigsetsize uint, flags int32) (uintptr, *kernel.SyscallControl, error) { 502 // Copy in the signal mask. 503 mask, err := copyInSigSet(t, sigset, sigsetsize) 504 if err != nil { 505 return 0, nil, err 506 } 507 508 // Always check for valid flags, even if not creating. 509 if flags&^(linux.SFD_NONBLOCK|linux.SFD_CLOEXEC) != 0 { 510 return 0, nil, linuxerr.EINVAL 511 } 512 513 // Is this a change to an existing signalfd? 514 // 515 // The spec indicates that this should adjust the mask. 516 if fd != -1 { 517 file := t.GetFile(fd) 518 if file == nil { 519 return 0, nil, linuxerr.EBADF 520 } 521 defer file.DecRef(t) 522 523 // Is this a signalfd? 524 if sfd, ok := file.Impl().(*signalfd.SignalFileDescription); ok { 525 sfd.SetMask(mask) 526 return 0, nil, nil 527 } 528 529 // Not a signalfd. 530 return 0, nil, linuxerr.EINVAL 531 } 532 533 fileFlags := uint32(linux.O_RDWR) 534 if flags&linux.SFD_NONBLOCK != 0 { 535 fileFlags |= linux.O_NONBLOCK 536 } 537 538 // Create a new file. 539 vfsObj := t.Kernel().VFS() 540 file, err := signalfd.New(vfsObj, t, mask, fileFlags) 541 if err != nil { 542 return 0, nil, err 543 } 544 defer file.DecRef(t) 545 546 // Create a new descriptor. 547 fd, err = t.NewFDFrom(0, file, kernel.FDFlags{ 548 CloseOnExec: flags&linux.SFD_CLOEXEC != 0, 549 }) 550 if err != nil { 551 return 0, nil, err 552 } 553 554 // Done. 555 return uintptr(fd), nil, nil 556 } 557 558 // Signalfd implements the linux syscall signalfd(2). 559 func Signalfd(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 560 fd := args[0].Int() 561 sigset := args[1].Pointer() 562 sigsetsize := args[2].SizeT() 563 return sharedSignalfd(t, fd, sigset, sigsetsize, 0) 564 } 565 566 // Signalfd4 implements the linux syscall signalfd4(2). 567 func Signalfd4(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 568 fd := args[0].Int() 569 sigset := args[1].Pointer() 570 sigsetsize := args[2].SizeT() 571 flags := args[3].Int() 572 return sharedSignalfd(t, fd, sigset, sigsetsize, flags) 573 }