mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
There is already some support for privileged executables before this change: file capabilities were taken into account when creating new processes inside the sandbox from external instigation (but not during execve(2)). set-user-id and set-group-id bits were never taken into account, and the Sentry behaved as if NO_NEW_PRIVS is always true. After this change, execve(2) and the external Exec entry point both take the set-user(group)-id bits and file capabilities into account. Because NO_NEW_PRIVS can no longer be assumed to be always set, a couple of extra checks to prevent privilege elevation during execve(2) are needed: the presence of a ptracer and the use of a shared fsContext. Moreover, execve had to be serialized with seccomp(2) when it is syncing filters to all threads in a group. Serializing execve with PTRACE_ATTACH and seccomp required some Task runState gymnastics. Task dumpability is reset when privilege elevation takes place and privilege elevation is denied for binaries living on nosuid mounts. To fix an old bug where some aux vectors were populated using data from the old pre-execve creds, the computation of the (file-privilege-augmented) creds during execve now takes place before the stack for the new program is set up. gvisor users who thus far have exec'd into the sandbox with UID as (sandbox) root will lose the caps an all-powerful namespace root'd have if: 1) the binary is a suid/guid binary 2) the owner of the binary is host root and there is no mapping for host root in the host user namespace of the sandbox. To avoid this surprise, the suid/sgid bits are ignored by default. Users can opt-in via the --allow-suid flag. One result of this change is that sudo now works inside the sandbox. PiperOrigin-RevId: 794414101
120 lines
3.7 KiB
Plaintext
120 lines
3.7 KiB
Plaintext
digraph {
|
|
subgraph {
|
|
App;
|
|
}
|
|
subgraph {
|
|
Interrupt;
|
|
InterruptAfterSignalDeliveryStop;
|
|
}
|
|
subgraph {
|
|
Syscall;
|
|
SyscallAfterPtraceEventSeccomp;
|
|
SyscallEnter;
|
|
SyscallAfterSyscallEnterStop;
|
|
SyscallAfterSysemuStop;
|
|
SyscallInvoke;
|
|
SyscallAfterPtraceEventClone;
|
|
SyscallAfterVforkStop;
|
|
SyscallReinvoke;
|
|
SyscallExit;
|
|
subgraph cluster_execve_and_its_creds_mutex {
|
|
style = dotted;
|
|
// execve itself
|
|
ExecveAfterExecveCredsLock; // creds mutex acquired
|
|
ExecveAfterSiblingExitStop; // siblings have all exited
|
|
// others
|
|
PtraceAfterExecveCredsLock;
|
|
SeccompAfterExecveCredsLock;
|
|
}
|
|
}
|
|
subgraph {
|
|
Vsyscall;
|
|
VsyscallAfterPtraceEventSeccomp;
|
|
VsyscallInvoke;
|
|
}
|
|
subgraph {
|
|
Exit;
|
|
ExitMain; // leave thread group, release resources, reparent children, kill PID namespace and wait if TGID 1
|
|
ExitNotify; // signal parent/tracer, become waitable
|
|
ExitDone; // represented by t.runState == nil
|
|
}
|
|
|
|
// Task exit
|
|
Exit -> ExitMain;
|
|
ExitMain -> ExitNotify;
|
|
ExitNotify -> ExitDone;
|
|
|
|
// Execution of untrusted application code
|
|
App -> App;
|
|
|
|
// Interrupts (usually signal delivery)
|
|
App -> Interrupt;
|
|
Interrupt -> Interrupt; // if other interrupt conditions may still apply
|
|
Interrupt -> Exit; // if killed
|
|
|
|
// Syscalls
|
|
App -> Syscall;
|
|
Syscall -> SyscallEnter;
|
|
SyscallEnter -> SyscallInvoke;
|
|
SyscallInvoke -> SyscallExit;
|
|
SyscallExit -> App;
|
|
|
|
// exit, exit_group
|
|
SyscallInvoke -> Exit;
|
|
|
|
// execve
|
|
SyscallInvoke -> ExecveAfterExecveCredsLock;
|
|
ExecveAfterExecveCredsLock -> ExecveAfterSiblingExitStop;
|
|
ExecveAfterExecveCredsLock -> SyscallExit;
|
|
ExecveAfterSiblingExitStop -> SyscallExit;
|
|
ExecveAfterSiblingExitStop -> App; // fatal signal pending
|
|
|
|
// Other syscalls that serialize with execve for correct creds computation.
|
|
// 1) ptrace (only for PTRACE_ATTACH and PTRACE_SEIZE)
|
|
SyscallInvoke -> PtraceAfterExecveCredsLock;
|
|
PtraceAfterExecveCredsLock -> SyscallExit;
|
|
PtraceAfterExecveCredsLock -> App;
|
|
// 2) seccomp (only SECCOMP_FILTER_FLAG_TSYNC)
|
|
SyscallInvoke -> SeccompAfterExecveCredsLock;
|
|
SeccompAfterExecveCredsLock -> SyscallExit;
|
|
SeccompAfterExecveCredsLock -> App;
|
|
|
|
// vfork
|
|
SyscallInvoke -> SyscallAfterVforkStop;
|
|
SyscallAfterVforkStop -> SyscallExit;
|
|
|
|
// Vsyscalls
|
|
App -> Vsyscall;
|
|
Vsyscall -> VsyscallInvoke;
|
|
Vsyscall -> App; // fault while reading return address from stack
|
|
VsyscallInvoke -> App;
|
|
|
|
// ptrace-specific branches
|
|
Interrupt -> InterruptAfterSignalDeliveryStop;
|
|
InterruptAfterSignalDeliveryStop -> Interrupt;
|
|
SyscallEnter -> SyscallAfterSyscallEnterStop;
|
|
SyscallAfterSyscallEnterStop -> SyscallInvoke;
|
|
SyscallAfterSyscallEnterStop -> SyscallExit; // skipped by tracer
|
|
SyscallAfterSyscallEnterStop -> App; // fatal signal pending
|
|
SyscallEnter -> SyscallAfterSysemuStop;
|
|
SyscallAfterSysemuStop -> SyscallExit;
|
|
SyscallAfterSysemuStop -> App; // fatal signal pending
|
|
SyscallInvoke -> SyscallAfterPtraceEventClone;
|
|
SyscallAfterPtraceEventClone -> SyscallExit;
|
|
SyscallAfterPtraceEventClone -> SyscallAfterVforkStop;
|
|
|
|
// seccomp
|
|
Syscall -> App; // SECCOMP_RET_TRAP, SECCOMP_RET_ERRNO, SECCOMP_RET_KILL, SECCOMP_RET_TRACE without tracer
|
|
Syscall -> SyscallAfterPtraceEventSeccomp; // SECCOMP_RET_TRACE
|
|
SyscallAfterPtraceEventSeccomp -> SyscallEnter;
|
|
SyscallAfterPtraceEventSeccomp -> SyscallExit; // skipped by tracer
|
|
SyscallAfterPtraceEventSeccomp -> App; // fatal signal pending
|
|
Vsyscall -> VsyscallAfterPtraceEventSeccomp;
|
|
VsyscallAfterPtraceEventSeccomp -> VsyscallInvoke;
|
|
VsyscallAfterPtraceEventSeccomp -> App;
|
|
|
|
// Autosave
|
|
SyscallInvoke -> SyscallReinvoke;
|
|
SyscallReinvoke -> SyscallInvoke;
|
|
}
|