encoding/json walked every payload on every call. ZAP reads a field at a
constant offset out of the buffer that arrived, and //tools/zap has
already stated those offsets for every payload, so the transport now asks
the payload for its own bytes and the parse step is gone.
The envelope collapses with it. clientCall and serverCall existed only
because JSON needed one type to hold an any and another to hold a
RawMessage; bytes are bytes, so one Call serves both ends. Framing comes
from the ZAP header, which declares its own length.
A payload that is nothing -- the *struct{} a method takes when it has no
argument or no result -- carries nothing. Anything else without a layout
fails the call naming the type, so a payload that would have arrived
silently empty does not arrive at all.
The methods that took a bare string or returned a bare int now take and
return named payloads, because a scalar has no layout to state and the
rest of the API was already shaped this way.
Co-authored-by: Hanzo Dev <[email protected]>
A prometheus Data held its labels in a map, and control.ExecArgs held the
live kernel objects an exec runs against -- a mount namespace, an fd
table, a limit set. Neither has offsets, so neither payload could state
a layout.
Labels become a list, which also retires the O(n^2) walk that existed to
read a map in sorted order. The kernel objects move to control.Env, which
is what the sentry supplies and what a call arriving on the wire cannot:
a namespace is a reference, not a value.
Every urpc payload now states its own wire.
Co-authored-by: Hanzo Dev <[email protected]>
A sandbox that answers "-gvisor" is upstream's binary. Telling the two apart
by config is a guess — the RuntimeClass, the containerd entry and the shim
options can all name our binary while the pod runs something else, which is
exactly what happened when an inline BinaryName was accepted by containerd and
never read by the shim. The guest's own uname is the one answer that cannot be
wrong about which kernel is running it.
Co-authored-by: Hanzo Dev <[email protected]>
Fix a panic when writing to cgroup v2 control files from outside the sandbox
(e.g., via Cgroups.WriteControlFiles / WriteControl), where writes occur
without an open in-sandbox VFS file descriptor (fd == nil). cgroup.procs now
safely falls back to context credentials with unconfined namespace migration,
and checkNSDelegateWrite skips namespace delegation checks. Add an integration
test for runsc cgroup v2 control file writes.
Also:
- Export cgroup2fs.InitHierarchy to initialize sandbox-wide cgroup2 state
and root controller enablement.
- Plumb CgroupNamespace through sentry lifecycle and task context to derive
initial container cgroup2 placements.
PiperOrigin-RevId: 978087817
Scope the signal mutex to just the tg.tty clear in CreateSession, matching how
CreateProcessGroup, JoinProcessGroup, and the exit path already call
handleOrphan without holding a signal mutex.
CreateSession held tg.signalHandlers.mu across the entire process group
manipulation, but it only needs that mutex to clear tg.tty. When setsid(2)
orphans the caller's old process group, decRefWithParent calls handleOrphan,
which locks the signal mutex of every thread group remaining in the group. If
the caller itself, or a sibling thread group that shares the caller's
SignalHandlers (created via clone(CLONE_VM|CLONE_SIGHAND) without CLONE_THREAD),
is still a member, handleOrphan re-locks the already-held, non-reentrant mutex
and the sentry deadlocks while holding TaskSet.mu, freezing the whole sandbox.
Regression test hangs prior to the fix.
Added pausing support for the timer(syntheticTimer)
the `AfterFunc` now won't trigger
when the kernel is paused.
The timer waits for all the AfterFunc functions
to complete during Pause. As of right now, all the
AfterFunc callbacks are not heavy, so it's okay.
When a new afterFunc is created:
- The event is added to the synthetic timer queue.
- AfterFuncScheduler sleeps until the next event in the queue.
- Triggers the expired events and repeats the cycle.
PiperOrigin-RevId: 971771243
Raw syscall exit events incorrectly fetched the field set registered for the corresponding raw enter point. Use SyscallRawExit so exit-specific context field selections are honored.
Signed-off-by: Yuhang Wei <[email protected]>
Add an efaproxy driver plug-in for AWS Elastic Fabric Adapter (EFA) devices
bound to the host `efa` driver. EFA's driver-private uverbs ABI carries no
userspace buffer pointers on CQ/QP CREATE: queue memory is kernel-allocated
and handed back via mmap keys in the CREATE response, which the core already
forwards to the host FD verbatim. PrepareCreateDMA is therefore a no-op; the
plug-in exists to register the "efa" driver name and to model EFA's MR_QUERY
driver-namespace method (used by libfabric to fetch RDMA read/write
interconnect IDs).
Model the standard AH object's destroy method (UVERBS_OBJECT_AH): EFA (SRD)
creates address handles via the legacy write path and destroys them through
the modern object, which the core must allow.
Extend the virtual RDMA sysfs for libfabric/hwloc topology discovery:
- device/driver symlink and /sys/bus/pci/drivers/<driver> tree, which
libfabric's EFA provider resolves during device discovery.
- Mirror each PCI node's raw config space ("config" file). hwloc (used by
aws-ofi-nccl to build the NCCL topology) reads it to recover the PCI
bridge bus-number registers; without it hwloc cannot reconstruct the
bridge hierarchy and aws-ofi-nccl aborts its topology write.
- Serve the per-port lid_mask_count attribute alongside the other port
attributes libibverbs reads from sysfs; ib_core creates it on every
port.
The sysfs integration tests cover the new driver tree and config mirroring.
Advertise a >= 5.12 kernel release in RDMA-enabled sandboxes so aws-ofi-nccl
enables dmabuf-based GPU memory registration (ibv_reg_dmabuf_mr), which the
proxy handles via the existing REG_DMABUF_MR path. Sandboxes without RDMA
keep the current 4.19 release to limit the bump's blast radius; a later
change can make the newer release the default.
Co-authored-by: Alessio Ricci Toniolo <[email protected]>
GPU profilers (Nsight Systems/CUPTI) build their trace timeline from
CLOCK_MONOTONIC_RAW. gVisor serves CLOCK_MONOTONIC_RAW as an alias of
CLOCK_MONOTONIC, this will drift from CLOCK_MONOTONIC_RAW breaking profiling.
When nvproxy is enabled with `capProfiling`, this change exposes
CLOCK_MONOTONIC_RAW as a clock distinct from CLOCK_MONOTONIC that tracks the
host's CLOCK_MONOTONIC_RAW (absolute, unadjusted). CLOCK_MONOTONIC is
unchanged. When profiling is disabled, CLOCK_MONOTONIC_RAW continues to alias
CLOCK_MONOTONIC as before.
This change extends the split filesystem checkpoint/restore feature to support
saving and restoring only a subset of filesystems (specified by paths). This
supports a "combined restore" mechanism where some memory files (tmpfs backings)
are restored from the filesystem checkpoint, while others are restored from the
main sentry checkpoint.
- Added `SplitFSCheckpointPaths` to `SaveOpts` to allow specifying paths for
partial FS checkpoints.
- Updated `createPrivateMemoryFile` to return whether it successfully loaded
state from the filesystem checkpoint.
- Track which memory files were loaded from the FS checkpoint during restore
(`fsCheckpointedMfs`) and pass this information to the kernel via context
(`CtxFSCheckpointedMemoryFiles`).
- In `loadPrivateMemoryFiles` (during sentry restore), only load memory files
from the sentry checkpoint if they were not already loaded from the FS
checkpoint.
- Added validation to ensure each memory file is restored from exactly one
source (no duplicates, and none are missed).
PiperOrigin-RevId: 964518735
This change implements split filesystem checkpoint and restore, allowing the
filesystem state to be saved and restored separately from the sentry state.
- Added `--split-fscheckpoint` flag to the `checkpoint` command to trigger
saving filesystem state separately. Added `--split-fsrestore` and
`--fs-restore-image-path` flags to `restore` and `create` commands to support
restoring from split files.
- Added `FSSave` and restore code for split filesystems.
- Implemented saving/restoring tmpfs state (MemoryFile pages and directory
structure) to/from a tar-like format.
- Refactored tar read/write path to support merging filesystem state in tar.go
- Implemented donating filesystem checkpoint FDs to the sandbox during
creation/restore.
- Added test to verify split checkpoint and restore.
PiperOrigin-RevId: 964380388
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
The idea is to make fscheckpoints be forward compatible (newer runsc versions
will successfully read fscheckpoints generated by an older runsc).
The exact details of how this plays out will obviously depend on ongoing runsc
runsc development (for how long to keep work-arounds for breaking changes, etc).
While this CL does enable forward compatible fscheckpoints by eliminating the
hard-matching requirement on runsc-version, please don't rely on it just yet.
PiperOrigin-RevId: 962306264
Acquire the t.tg.signalHandlers.mu lock before reading
t.tg.exitStatus for the seccheck.PointTaskExit event to prevent
a data race with prepareGroupExitLocked.
PiperOrigin-RevId: 960540807
When --mount-cgroup-v2 is enabled, a container whose spec includes a
cgroup mount is now given its own cgroup "/<cid>" in the cgroup2
hierarchy, with its init process placed there.
Cgroup namespaces from the spec are now honored, mirroring PID
namespace policy: no entry means the root namespace, an entry with a
path joins the container that declared the same path, and an entry
without a path gets a new namespace rooted at the container's cgroup.
Since a fresh cgroup2 mount is rooted at the mounting namespace's
root, a private-namespace container's /sys/fs/cgroup shows only its
own subtree, as on Linux, with no need for bind mounts.
At boot the sentry now enables nsdelegate and delegates controllers
to per-container cgroups via the root cgroup.subtree_control. Exec
sessions join the container's cgroup and cgroup namespace, like
runc exec. Per-container "runsc events" and read-control queries
now resolve for any container with a cgroup mount.
Note two differences from the existing v1 support. In v1 we bind mount:
the per-container dir "/$cid" of each controller hierarchy appears as
/sys/fs/cgroup/<controller>. With v2 no bind mounts are needed: a fresh
cgroup2 mount is rooted at the mounting namespace's root, so honoring
the spec's cgroupns request yields the scoped view naturally. (Binding
a subtree a la v1 was not an option anyway: systemd explicitly rejects
a sub-hierarchy mounted without a matching cgroup namespace.) Second,
on container destroy we now make a best-effort, recursive attempt to
remove the container's cgroup subtree; v1 leaves its per-container
dirs behind.
The root container is not special-cased. As with v1, where even the
root container gets container-id-stamped cgroup dirs and the stats
queries they enable, it gets its own "/$root_cid", and its cgroup
namespace comes from the spec like everyone else's. Docker and
Kubernetes both request a private cgroup namespace for every container
on cgroup2 hosts, so in practice the root container sees its cgroup as
a pleasing "/" rather than "/$root_cid"; a spec with no cgroupns entry
(e.g. docker run --cgroupns=host) instead sees the full sandbox
hierarchy, as on Linux. One consequence of the private default: in a
multi-container sandbox the root container cannot see the other
containers' cgroups (namespace roots are not hierarchical). I don't
expect that to be problematic, and a spec without a cgroupns entry
regains the full view if ever needed.
PiperOrigin-RevId: 960153510
Adds initial scaffolding for eBPF in gVisor. It implements the bpf(2) syscall
with support for BPF_PROG_LOAD, BPF_PROG_QUERY, and BPF_PROG_ATTACH.
Necessary for the cgroups v2 flag to be enabled by default, as this fixes
Docker-in-gVisor with cgroups v2.
NewSCMCredentials previously resolved the specified PID into a thread group with separate calls to ThreadGroupWithID() and PIDNamespacedIDs().
Both of these functions separately take and release the TaskSet lock.
This causes a race condition where between the two function calls, the thread group might get reaped, leading to the panic() being reached.
This commit addresses this issue by moving the thread group resolution/PID namespace map creation into a single critical section.
A regression syscall test is also included.
Reported-by: [email protected]
This change extends the filesystem checkpointing to support configuring
multiple independent paths to snapshot.
- Updated `runsc fscheckpoint` to support a repeatable `--path` flag, allowing
users to specify multiple `<container_id>:<path>` pairs.
- Annotations: Introduced `dev.gvisor.internal.fscheckpoint.paths` annotation
supporting a comma-separated list of paths.
- Refactored the sentry matching logic to support multiple paths with fallback
for "all-tmpfs" or global paths.
- Verified that checkpoint and restore work correctly for shared volumes
("share=pod") when sharing container paths are specified.
- Added container tests covering multi-path checkpoint and shared volumes.
PiperOrigin-RevId: 956120278
This mount option turns cgroup namespaces into delegation boundaries,
which results in the following two behaviors:
First, resource control. A cgroup's resource-control files carve out
the parent's resources, so they belong to the delegater, not to the
subtree's occupants. Accordingly, tasks in a non-init cgroup namespace
may no longer write to interface files of their own namespace root.
The delegatable files (cgroup.procs, cgroup.subtree_control) are exempt.
Subtree tasks cannot change what share of resources the subtree receives,
but remain free to organize processes and distribute that share within it.
Second, containment. Migration (including via CLONE_INTO_CGROUP) now
requires that both the source and destination cgroups be descendants of
the cgroupns root of the task performing the migration, failing with
ENOENT otherwise (actually it is the cgroupns of the task that opened the
fd for the migration file: this detail forces me to snapshot the cgroupns
against the fd, increasing the size of this patch).
PiperOrigin-RevId: 954892289
This change introduces an LRU cache (ExecveHashCache) and multi-algorithm
calculation engine (file_hash.go) to store and resolve SHA-256 and SHA-1
digests of executables during execve syscalls.
PiperOrigin-RevId: 952257971
This change adds the execfn field to the ExecveInfo seccheck point.
This field preserves the original, unresolved pathname passed to
execve(2) (used for AT_EXECFN), distinguishing it from BinaryPath,
which contains the fully resolved filesystem path after symlink and
interpreter resolution.
Tests have been updated to verify the distinction between
BinaryPath, Execfn, and Argv[0].
PiperOrigin-RevId: 952211288
Much like how cgroup v1 control files are already queryable. "runsc events"
now consults cgroup2 control files when --mount-cgroup-v2 is true, for cpu
and memory usage stats.
Currently runsc does not place each in-sandbox container is its own cgroup2
node like it does with cgroup v1, hence we just test queries against the root
cgroup2 node for now.
PiperOrigin-RevId: 950984770
This change introduces a new field `binary_overlayfs_lower` in the
`ExecveBinaryInfo` seccheck point. This field is set to true if the executed
binary is found on one of the lower layers of an overlay filesystem. A helper
function `overlay.IsOnLower` is added to determine this. The existing
`binary_overlayfs_upper` field is also clarified to represent any file on
the upper layer.
PiperOrigin-RevId: 949711533
cgroup namespaces are non hierarchical and they are defined primarily by a
"root" cgroup node. The init cgroup namespaces's root node is the true root of
the (only) cgroup2fs tree. The root node of other cgroup namespaces is the
cgroup node of the task at the time of namespace creation.
Residing in a cgroup namespace affects tasks this way:
1) The views into /proc/[pid]/cgroup and the "root" field under
/proc/[pid]/mountinfo are virtualized: they are rendered relative to the
reading task's cgroupns.
2) mount()ing a cgroup2 fs furnishes only a subtree of the full cgroup2fs
tree, rooted at the "root" cgroup of the hosting cgroupns.
Fixes#11989
PiperOrigin-RevId: 948882249
This change introduces a new seccheck field, FieldSentryExecveFdInfo, for the
Execve trace point. When enabled, this field collects information about file
descriptors 0, 1, and 2 (stdin, stdout, stderr) and populates the new stdin,
stdout, and stderr fields in the ExecveInfo proto. The collected FdInfo
includes the file path, mode, inode, whether it's on an overlayfs upper
layer, and socket details (local/remote addresses) if the FD is a socket.
PiperOrigin-RevId: 948482163
This change includes the creation time (ctime) of the executable binary in the
seccheck ExecveInfo and MmapInfo.
The Timespec proto message is moved to common.proto for reuse.
PiperOrigin-RevId: 948385290
This change adds a new field `is_exec_session` to the seccheck Context. This
field is set to true if the task originated from an exec session, such as
those created by `runsc exec` or `kubectl exec`.
PiperOrigin-RevId: 948071517
This change refactors the network configuration flow during sandbox restore
and defers the creation of network links and routes in runsc to run after
seccomp filters are installed.
- Replaced ReplaceConfig with ResetConfig in inet.Stack. Introduced
inet.NetworkArgs to configure the stack during restore, updating k.LoadFrom
to use it.
- Renamed CreateLinksAndRoutes URPC to SetNetworkArgs, which now configures
host sockets before seccomp is installed, deferring link/route creation to run
after seccomp.
- Fixed S/R support by saving and restoring limit/burst state.
- Minor seccomp filter adjustments and test updates.
PiperOrigin-RevId: 945995430
This change introduces a new field `binary_overlayfs_upper` to the
`ExecveBinaryInfo` seccheck point. This field is set to true if the executable
being run is located on the upper layer of an overlay filesystem. A new helper
function `overlay.IsCopiedUp` is added to check this condition.
PiperOrigin-RevId: 944568906
The value has no effect, but it is stored and inherited across fork().
Unlike Linux, our default value is 0.
Elasticsearch >=v9.3.0 requires this.
PiperOrigin-RevId: 944228419
The cgroup v2 fs is initialized early in the boot process, so that every task
in the sandbox resides in at least the root v2 cgroup. A new runsc flag
--mount-cgroup-v2 has been added: this controls whether runsc mounts a
cgroupv2 filesystem at /sys/fs/cgroup automatically (currently it always
mounts a v1 hierarchy at this path). This flag also gates whether userspace
can mount a cgroup2 fs. When this flag is false, which is the default, all
tasks in the sandbox reside forever in the root cgroup.
Like in Linux, the v2 hierarchy is deemed the default owner of a controller,
that is, until the corresponding v1 hierarchy is mounted: then, the v1 tree
steals ownership of that controller and it remains this way till as long as
a v1 mount exists. In other words, hybrid mode is supported, even if such
workloads are rare these days.
The pids controller is the only controller implemented in full: it serves
as validation for the unified hierarchy. The memory controller can be used
to learn the usage stats of a subtree: but like the current v1 implementation,
and unlike Linux, it doesn't achieve this through charging up the hierarchy
during allocation, instead it queries pgalloc for every active controller's
id. And it does no enforcing. The cpu and cpuset controllers are mere stubs,
like in the current v1 implementation.
The following are supported:
* General matters of topology: cgroup.subtree_control, cgroup.controllers,
cgroup.procs etc
* CLONE_INTO_CGROUP
* cgroup.kill
* cgroup.events
* A working pids controller and its events files
* A minimal memory controller that just reports mem usage
* Stubbed cpu and cpuset controllers
The following are NOT supported:
* threaded cgroups
* cgroup namespaces
* BPF_PROG_TYPE_CGROUP_DEVICE
* cgroup.freeze
Updates #13007
PiperOrigin-RevId: 943519748