Reading a ZAP result writes every field its layout states, the file payload
included, so files attached before decoding were overwritten with none. A
frame whose header is not ZAP is refused at the magic rather than read as a
length.
Co-authored-by: Hanzo Dev <[email protected]>
It was the only thing in the tree importing google.golang.org/grpc, and it
reaches no runsc build path — 71 files of network conformance tests against a
posix_server that is not part of the sandbox. The control plane is urpc, and
now nothing here speaks gRPC at all.
Co-authored-by: Hanzo Dev <[email protected]>
renameat2(2) support was added in 61f761343f ("Implement renameat2."),
but only for the gofer filesystem; tmpfs and overlayfs still return
EINVAL for RENAME_EXCHANGE.
Implement RENAME_EXCHANGE in tmpfs by swapping the two dentries between
their parent directories. When the exchanged files differ in type, the
parents' link counts (for "..") and the exchanged directory's reference
on its parent are transferred.
Implement RENAME_EXCHANGE in overlayfs by copying up the destination
file (and its descendants, if it is a directory) in addition to the
source, and then exchanging both files on the upper layer. Unlike a
regular rename, no whiteout is created at the source location, since
both locations remain occupied. Exchanged directories are marked opaque
at their new locations to prevent merging with lower layer directories
there.
RENAME_EXCHANGE permits the two files to differ in type and does not
require a directory being exchanged to be empty, but exchanging a file
with an ancestor directory must fail with EINVAL; see Linux's
fs/namei.c:__start_renaming(). The gofer filesystem previously required
both files to have the same type; lift that restriction, and update
parent link counts when files of different types are exchanged across
directories.
The RENAME_EXCHANGE syscall tests no longer accept EINVAL; they are
skipped where the flag remains unsupported, i.e. on FUSE and on gVisor
kernels other than runsc. New tests cover mixed-type exchanges and
exchanges with ancestor directories.
Fixes#7895
The cpu controller tracks each task's CPU via a per-instance baseline
snapshot plus a cumulative total for exited tasks, but it never walked
the whole accounting domain when reporting cpu.stat and never reconciled
that state when a controller was disabled or when a task migrated within
a single controller's domain. This caused three accounting errors, each
covered by a new test:
- Live tasks in descendant cgroups that had not enabled their own cpu
controller were absent from the ancestor's cpu.stat until they
exited, even though Linux aggregates descendant usage into the
ancestor continuously.
- Migrating a task between two cgroups sharing the same nearest cpu
controller reset its baseline, discarding the pre-migration CPU.
- Disabling +cpu discarded the controller's accumulated usage instead
of reparenting it (Linux folds an offlined css's stats into parent).
Sum the whole domain (the controller's cgroup plus every descendant
without its own cpu controller, recursing into descendants that do) when
reading cpu.stat; leave the baseline untouched on same-instance
migration; and on disable, migrate the domain's tasks to the parent's
nearest cpu controller and fold the accumulated total into it.
PiperOrigin-RevId: 974821312
Enabling +pids in cgroup.subtree_control creates child pids controllers
with committed = 0, ignoring tasks already present in those cgroups.
pids.current then underreports, and migrating such a task away drives
it negative, since attach() applies deltas unguarded.
Charge a newly instantiated pids controller for the tasks already in
its subtree, both when a parent enables it (rebuildCtrlsLocked) and
when it is returned to the root (returnController). Adds a regression
test.
PiperOrigin-RevId: 974763124
updatePopulated is called when a cgroup's own tasksCount crosses the
0<->1 boundary, but propagated the change to ancestor
nrPopulatedChildren counters even when the cgroup stayed populated
through a child. Draining a mid-level cgroup then made ancestors report
"populated 0" with live tasks below, and the child's later drain
decremented ancestors a second time, leaving the counter permanently
negative.
Skip the notification/propagation walk when the cgroup still has
populated children. Adds a regression test covering both the false
"populated 0" and the stuck-negative counter.
PiperOrigin-RevId: 974662615
Test incorrectly assumed that epoll_wait returns events in the
exact same order that the file descriptors were registered.
Because epoll_wait returns the events in a randomized order after a
save/restore, we can no longer assume the modified file descriptor
will be at the very end of the result array.
This test started flaking since
https://github.com/google/gvisor/commit/713ef7d7d02a.
PiperOrigin-RevId: 974280975
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.
The peer payload is sliced at the size of a struct ifinfomsg before anything measures it, so 4 bytes panic the Sentry and take the sandbox with it. Any user reaches it after unshare -Ur -n.
Check the length instead of re-testing a lookup that already succeeded. A short payload now answers EINVAL.
Fixes#14516
gVisor returned `ENOSYS` for `copy_file_range(2)`, causing toolchains and
runtimes without fallback paths (such as Zig during linker output generation)
to fail inside sandboxes.
Implement `copy_file_range` as a generic buffered copy in the Sentry to
maintain backing filesystem independence and avoid widening the Sentry seccomp
filter. Argument validation and error handling mirror Linux kernel
`fs/read_write.c` semantics, including offset range checks, cross-device copy
support, and same-file overlap detection.
Add `copy_file_range_test` covering offset handling, short copies, overlap
detection, and Linux errno parity across runsc platforms.
PiperOrigin-RevId: 973465473
It's just a matter of exposing the option via sysfs. Capped to same max as
Linux, to follow convention of what we're already doing with nr_open.
PiperOrigin-RevId: 972901017
As of Linux commit 5d39580f68e6, SO_ATTACH_FILTER requires
CAP_NET_ADMIN for TCP sockets.
Skip in tests if we don't have it, and update Netstack to require it
too.
This change fixes a mount leak, where a failed bind mount clone would still
remain as part of the mount peergroup. This clone would be found via as the
next entry in mnt.sharedEntry for a new MS_SLAVE mount. The fix is to simply
set the new clone's propagation to MS_PRIVATE, which makes it remove itself
from the peer ring.
This error is demonstrated pretty clearly in the included unit test
(which is mostly LLM-generated, but is relatively straighforward).
Reported-by: [email protected]
PiperOrigin-RevId: 972688916
Removes nsfs/cgroupfs's exemptions from umounted checks when bind mounting, and
exempts them from mount namespace checks only for non-recursive binds.
Documents the invariant that umounted children should never have mounted
parents more clearly with a checkInvariants panic in cloneMountTree.
PiperOrigin-RevId: 972149358
redhat/ubi10-init covers a second systemd lineage: RHEL 10, systemd
v257, which mandates cgroup v2. The test boots it and checks for failed
units and a working transient unit.
images/systemd/ built systemd from source for a past investigation and
is referenced by nothing.
PiperOrigin-RevId: 970125419
With tests for sandboxing, multiuser, and dockerd:
- Exec sandboxing knobs: PrivateTmp, ProtectSystem=strict, User=, and
NoNewPrivileges.
- Multiuser operation: two users with their own service managers,
daemons, journals, and delegated cgroups, isolated from each other.
User commands run through systemd-machined, which resolves users
created inside the sandbox (docker exec --user cannot).
- TestSystemdDocker now runs a container instead of stopping at pull.
These tests rely on the two preceding fixes: the NoNewPrivileges probe
reads the new NoNewPrivs line in /proc/[pid]/status, and user-unit
sandboxing fails unless mountinfo shows nodev.
PiperOrigin-RevId: 970106945
gVisor stored, locked, and enforced MS_NODEV, but never rendered it. A
remount replaces a mount's whole flag set, so to add a flag userspace
must read the mount's current flags from mountinfo and pass them back.
With nodev missing from that read-back, systemd's sandboxing code
unknowingly requested a remount that would clear nodev — which the
kernel rightly refuses (EPERM) in user namespaces, where preexisting
flags are locked.
Also fix noatime rendering, which overwrote the rw/ro field instead of
appending to it, and match Linux's flag order. Add a syscall test for
both files.
PiperOrigin-RevId: 970083172
- Add RuntimeTypeMicroVM with kata-clh handler, microvm RuntimeClass
overhead, node selector, and toleration configurations.
- Automatically configure nested virtualization when creating MicroVM
nodepools.
- Add GKE API environment (--env) and endpoint override (--endpoint)
support for testing against common GKE environments (prod, staging,
staging2, test). User flags take precedence over environment variables.
- Store endpoint in TestRange and Cluster protos to allow locating
and deleting clusters across environments.
- Calculate memory requests with headroom to satisfy node allocatable
limits on GKE nodepools.
PiperOrigin-RevId: 970078173
Since Linux 6.16 (7d8d93fdde50), SO_PASSCRED is restricted to AF_UNIX,
AF_NETLINK, and AF_BLUETOOTH sockets; getsockopt on inet sockets fails
with EOPNOTSUPP. This surfaces natively on new kernels and through
hostinet passthrough, while netstack keeps the old semantics. Accept
either behavior.
PiperOrigin-RevId: 968655712
Private file mappings can acquire owned huge PMAs after a write breaks
copy-on-write. MemoryManager.Decommit treats those PMAs like private
anonymous memory when MADV_DONTNEED covers only part of a huge page. It
decommits the MemoryFile range in place, replacing discarded file data with
zeroes. Linux instead discards the private copy so later faults reload the
mapped file.
Limit the partial huge-page decommit optimization to anonymous VMAs. Let
file-backed private PMAs follow the normal invalidation path, which drops the
copied pages and restores file contents on the next fault.
Add a syscall test that modifies a huge private file mapping and applies
MADV_DONTNEED to an interior page.
Seems that GNU tar extraction has been broken in gVisor since 75b03fd
(11/15/2025), which started using openat2(2) to address CVE-2025-45582.
tar uses openat2(2) for the RESOLVE_BENEATH flag which allows scoping
the path resolution underneath the specified dirfd.
This commit implements openat2(2) in gVisor, with support for all flags
supported by Linux: RESOLVE_BENEATH, RESOLVE_IN_ROOT, RESOLVE_CACHED,
RESOLVE_NO_MAGICLINKS, RESOLVE_NO_SYMLINKS, and RESOLVE_NO_XDEV.
This commit also introduces VirtualFilesystem.renameSeq, a global
sequence counter that along with mountSeq detects mount or rename
operations that race with scoped traversals.
A final "resolved-path-is-under-dirfd" check is performed after
the traversal. This is for two reasons: (1) in case of a bug in
any of the above logic, or (2) in case of an (extremely unlikely)
attack where mountSeq overflows by exactly 2^32 during a path
resolution. Unfortunately, due to the way path traversal in gVisor
is tightly coupled to the operation being performed by a VFS method,
using scoped traversals in an operation that *mutates* anything will
be difficult, since without major refactoring, the check must happen
after the side effect has taken place.
Currently, Linux only exposes scoped traversals through openat2(2),
so destroying the created fd is all we need to do if the final check
fails. (As a result of this limitation, most VFS functions have been
modified to reject scoped traversals "just-in-case".)
The RESOLVE_NO_XDEV implementation has a slight divergence from
Linux. It is a bit looser, permitting absolute symlinks in any case
where the root dentry's mount matches the mount the traversal is
locked to. Linux's behavior here is likely a bug, and since we can
safely be *more* permissive, there's not much reason to match it.
This commit also adds syscall tests and an strace formatter for
openat2(2).
The shutdown notification paths only notified ReadableEvents and
WritableEvents, so a poller waiting only for POLLHUP or POLLRDHUP was
never woken and slept until its timeout. Linux wakes all waiters via
sk_state_change(). Notifications now include EventRdHUp and EventHUp
where the closed direction can newly satisfy them; over-notifying is
harmless since woken waiters re-check readiness.
PiperOrigin-RevId: 966685883
Added:
- NAT(SNAT/DNAT) targets to perform network address and port translation.
- XTNATTargetV0, XTNATTargetV1, and XTNATTargetV2 ABI support.
- Fixed NFNATRange2(nf_nat_range2) struct and it's size.
- Unit and syscall tests.
Ref: net/netfilter/xt_nat.c
PiperOrigin-RevId: 966381482
When an AF_UNIX socket is bound to a path, the resulting BoundEndpoint is
stored on the gofer inode, and other processes reach it by path: they walk
to the dentry, then pull the endpoint off its inode and connect. Crucially,
a bound socket stays connectable even when no file descriptor is holding
that path open.
The gofer refcounting invariant is: "An additional reference is held on all
synthetic dentries, and on all dentries for which endpoint is non-nil, until
they are unlinked or invalidated."
This purpose of this invariant is for a host-backed bound UDS to stay
resolvable by path even when no FD holds it. A gofer dentry at refs == 0 is
eligible for reclaim; reclaiming it tears down the inode and drops the
HostBoundEndpoint (and its host FD). So the filesystem pins every endpoint-
bearing dentry with one extra ref, held from bind until the name goes away.
This extra ref is dropped unconditionally, guarded only by `endpoint != nil`
in many places: unlinkAt, RenameAt, revalidation/invalidation, filesystem
teardown etc. (These drop paths assume that the invariant holds.)
To establish the invariant the extra ref is taken in the bind paths sure, but
we were missing a reference increment for a dentry that later comes to point
at the same endpoint-bearing inode. This can happen either due to a hard link
or another walk that lands on the same inode.
PiperOrigin-RevId: 966116353
Added:
- `xt_MASQUERADE` target extension.
Masq can dynamically rewrites the packet's source IP
to match the outgoing interface's primary IP.
- Masq Revision 0 ABI.
- Unit and syscall tests.
Ref: net/netfilter/xt_masquerade.c
PiperOrigin-RevId: 965062213
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