A tty inode was kept alive by a single ownership chain: the stdio file
description's reference on the import-time dentry. Everything else that used
the inode referred to it uncounted: a file description opened via /dev/tty
pins only the devtmpfs dentry, and the controlling-terminal association
(ThreadGroup.tty) is a bare pointer.
PiperOrigin-RevId: 962479941
Adds stub implementations for:
- sched_setattr(2)
- sched_getattr(2)
- ioprio_set(2)
- ioprio_get(2)
"Support" (with no effect) is included for SCHED_OTHER (referred to in Linux
as SCHED_NORMAL), SCHED_BATCH, and SCHED_IDLE. sched_getscheduler(2) and
sched_setscheduler(2) are updated to support all three as well.
For ioprio_set, the configured I/O priority has no effect.
PiperOrigin-RevId: 938270335
Thus far we were silently ignoring this flag.
While writing the syscall test for this change I realized that we were
using the async-signal-unsafe `FileDescriptor.reset()` (It's unsafe because
it eventually calls `getenv()`) and `exit()`
in various `fork()` contexts, so I fixed the affected syscall tests.
PiperOrigin-RevId: 925064507
This patch introduces pidfd support roughly up to Linux 6.8. Linux selftests
at this version pass, and are now run as an //image_test target. Some features,
like PIDFD_THREAD, that occur later than 6.8 in Linux, are included.
It includes:
- These new syscalls:
- pidfd_open()
- pidfd_getfd()
- pidfd_send_signal()
- New aspects to these existing syscalls:
- waitid() in its support of P_PIDFD
- clone()/clone3() in their support of CLONE_PIDFD
- poll()/epoll()/select() in their support for pidfds
- setns() in its support for pidfds
- pid introspection via /proc/[pid]/fdinfo/[pidfd]
It excludes:
- pidfdfs: pidfds are backed by the anon inode right now
- ioctls to retrieve namespace fds using a pidfd
- process_madvise()
Updates #5839.
PiperOrigin-RevId: 908341658
## Summary
This patch adds capability and permission checks that the Linux kernel enforces but gVisor currently omits. Each fix was verified against native Linux behavior using `bazel test` on both native and `runsc_ptrace` platforms.
## Changes
### 1. `SO_BINDTODEVICE`: Add `CAP_NET_RAW` check
**File:** `pkg/sentry/socket/netstack/netstack.go`
**Linux reference:** `net/core/sock.c:sock_setsockopt()` checks `ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW)`
**Evidence this is unintended:** gVisor's own test suite asserts `"CAP_NET_RAW is required to use SO_BINDTODEVICE"` (`test/syscalls/linux/socket_bind_to_device.cc:52`), and `SO_RCVBUFFORCE` in the same file already correctly checks `CAP_NET_ADMIN`.
### 2. `mknod(S_IFBLK/S_IFCHR)`: Add `CAP_MKNOD` check
**File:** `pkg/sentry/syscalls/linux/sys_file.go`
**Linux reference:** `fs/namei.c:vfs_mknod()` checks `capable(CAP_MKNOD)` for block/char device creation
**Evidence this is unintended:** `CAP_MKNOD` is defined (`pkg/abi/linux/capability.go:56`), parsed from OCI specs (`runsc/specutils/specutils.go:491`), and has strace formatting — but is never checked anywhere. Zero `HasCapability` calls for it exist in the codebase.
### 3. `sched_setaffinity`: Add UID match / `CAP_SYS_NICE` check
**File:** `pkg/sentry/syscalls/linux/sys_thread.go`
**Linux reference:** `kernel/sched/core.c:check_same_owner()` requires EUID match or `CAP_SYS_NICE`
**Impact:** Without this check, any unprivileged process could modify another process's CPU affinity mask.
### 4. `setpriority`: Add UID match / `CAP_SYS_NICE` check
**File:** `pkg/sentry/syscalls/linux/sys_thread.go`
**Linux reference:** `kernel/sys.c:set_one_prio()` requires UID match or `CAP_SYS_NICE`
**Impact:** Without this check, any unprivileged process could change another process's scheduling priority.
## Testing
Tests added in `test/syscalls/linux/capability_checks.cc`, verified on both native Linux and gVisor:
```
bazel test //test/syscalls:capability_checks_test_native → 6/6 passed
bazel test //test/syscalls:capability_checks_test_runsc_ptrace → 4 passed, 2 skipped
```
The 2 skipped tests are the mknod positive cases (creating device nodes with `CAP_MKNOD`), which are skipped on gVisor because the sandbox does not permit device node creation regardless of capabilities.
| Test | What it verifies |
|------|-----------------|
| `SoBindToDeviceCapTest.RequiresCapNetRaw` | `EPERM` without `CAP_NET_RAW` |
| `MknodCapTest.CharDevRequiresCapMknod` | `EPERM` for `S_IFCHR` without `CAP_MKNOD` (native only) |
| `MknodCapTest.BlockDevRequiresCapMknod` | `EPERM` for `S_IFBLK` without `CAP_MKNOD` (native only) |
| `MknodCapTest.FifoDoesNotRequireCapMknod` | `S_IFIFO` succeeds without `CAP_MKNOD` |
| `SchedSetaffinityCapTest.OtherUidRequiresCapSysNice` | `EPERM` without UID match or `CAP_SYS_NICE` |
| `SetpriorityCapTest.OtherUidRequiresCapSysNice` | `EPERM` without UID match or `CAP_SYS_NICE` |
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/gvisor/pull/12872 from petrmarinec:fix/missing-capability-checks 70b4e0fa308ba182e7916112e90aed40cdea75f3
PiperOrigin-RevId: 903343461
Co-authored-by: Hanzo Dev <[email protected]>
In execveat, when dirfd is not AT_FDCWD and pathname is not absolute, the
pathname is now constructed using /dev/fd/. Earlier, we were using MappedName()
which could return paths with " (deleted)" suffix for deleted files, making
them inaccessible from filesystem traversal.
This is consistent with that Linux does, see fs/exec.c:alloc_bprm().
Suggested-by: @dean-deng
Fixes#1090
PiperOrigin-RevId: 850502410
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
From setpgid manpage,
EACCES - An attempt was made to change the process group ID of one
of the children of the calling process and the child had
already performed an execve(2) (setpgid(), setpgrp()).
This CL makes gVisor implement this rule and updates the exec test
suite accordingly.
TESTED: http://sponge2/7f364e8a-4f82-463e-ba62-79234c4d054d
PiperOrigin-RevId: 727095560
This change introduces the nsfs file system. Each new namespace allocates
a new nsfs inode.
Here are reasons why we need these inodes:
* each namespace has to have an unique id.
* proc/pid/ns/ contains one entry for each namespace. Bind mounting one of
the files in this directory to somewhere else in the filesystem keeps the
corresponding namespace alive even if all processes currently in
the namespace terminate.
* setns() allows the calling process to join an existing namespace specified
by a file descriptor.
PiperOrigin-RevId: 550694515
This will be used to plumb the syscall number through to a counter metric that
exports the number of times an unimplemented syscall has been called.
Plenty of syscall implementations call `EmitUnimplementedEvent` for flags and
settings that are not implemented. With `sysno` available, they will be able
to plumb that bit of information through.
PiperOrigin-RevId: 518635831
Removes package syserror and moves still relevant code to either linuxerr
or to syserr (to be later removed).
Internal errors are converted from random types to *errors.Error types used
in linuxerr. Internal errors are in linuxerr/internal.go.
PiperOrigin-RevId: 390724202
Update all instances of the above errors to the faster linuxerr implementation.
With the temporary linuxerr.Equals(), no logical changes are made.
PiperOrigin-RevId: 382306655
Remove three syserror entries duplicated in linuxerr. Because of the
linuxerr.Equals method, this is a mere change of return values from
syserror to linuxerr definitions.
Done with only these three errnos as CLs removing all grow to a significantly
large size.
PiperOrigin-RevId: 382173835
Split usermem package to help remove syserror dependency in go_marshal.
New hostarch package contains code not dependent on syserror.
PiperOrigin-RevId: 365651233
The syscall package has been deprecated in favor of golang.org/x/sys.
Note that syscall is still used in the following places:
- pkg/sentry/socket/hostinet/stack.go: some netlink related functionalities
are not yet available in golang.org/x/sys.
- syscall.Stat_t is still used in some places because os.FileInfo.Sys() still
returns it and not unix.Stat_t.
Updates #214
PiperOrigin-RevId: 360701387
This reduces confusion with context.Context (which is also relevant to
kernel.Tasks) and is consistent with existing function kernel.LoadTaskImage().
PiperOrigin-RevId: 342167298
- Added fsbridge package with interface that can be used to open
and read from VFS1 and VFS2 files.
- Converted ELF loader to use fsbridge
- Added VFS2 types to FSContext
- Added vfs.MountNamespace to ThreadGroup
Updates #1623
PiperOrigin-RevId: 295183950
Because the abi will depend on the core types for marshalling (usermem,
context, safemem, safecopy), these need to be flattened from the sentry
directory. These packages contain no sentry-specific details.
PiperOrigin-RevId: 291811289
sys_clone has many flavors in Linux, and amd64 chose
a different one from x86(different arguments order).
Ref kernel/fork.c for more info.
Signed-off-by: Haibo Xu <[email protected]>
Change-Id: I6c8cbc685f4a6e786b171715ab68292fc95cbf48
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/gvisor/pull/1545 from xiaobo55x:clone 156bd2dfbc63ef5291627b0578ddea77997393b2
PiperOrigin-RevId: 290093953
When an interpreter script is opened with O_CLOEXEC and the resulting fd is
passed into execveat, an ENOENT error should occur (the script would otherwise
be inaccessible to the interpreter). This matches the actual behavior of
Linux's execveat.
PiperOrigin-RevId: 277306680
This change simplifies the function signatures of functions related to loading
executables, such as LoadTaskImage, Load, loadBinary.
PiperOrigin-RevId: 276821187
Adds feature to launch from an open host FD instead of a binary_path.
The FD should point to a valid executable and most likely be statically
compiled. If the executable is not statically compiled, the loader will
search along the interpreter paths, which must be able to be resolved in
the Sandbox's file system or start will fail.
PiperOrigin-RevId: 260756825
The previous commit adds WNOTHREAD support to waitid, so we may as well
complete the upstream change.
Linux added WCLONE, WALL, WNOTHREAD support to waitid(2) in
91c4e8ea8f05916df0c8a6f383508ac7c9e10dba ("wait: allow sys_waitid() to
accept __WNOTHREAD/__WCLONE/__WALL"). i.e., Linux 4.7.
PiperOrigin-RevId: 249560587
Change-Id: Iff177b0848a3f7bae6cb5592e44500c5a942fbeb