Low storage space is a primary reason that `docker kill` might stall, so this
will allow us to diagnose clear_docker_containers failures more clearly.
PiperOrigin-RevId: 972891010
In the case of a partly umounted mount, we should only drop the reference on
the parent, not the mount point itself.
Keep the mount point reference since the umounted mount still refers to its
mount point.
PiperOrigin-RevId: 972771131
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
test/runner/main.go has `performanceWarningRegexp` set as:
```
var performanceWarningRegexp =
regexp.MustCompile(`(?i).*(slows?|slowing).*(startup|teardown).*`)
```
the existing warning did not match this regex, causing flaky readv tests in
buildkite.
This should fix it.
PiperOrigin-RevId: 970157268
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).
Hopefully will (a) allow the autoscaler to do its job more effectively and
(b) get the tests to run in a more consistent environment.
Part 1 only changes the queues that *need* to change due to queue name changes.
PiperOrigin-RevId: 967505295
AFAICT previously the function was parsing the Docker *client* version, since
the output of `docker version` has the client version first, which gets picked
up by the `re.FindStringSubmatch()` since it finds the _first_ match:
```
$ docker version
Client: Docker Engine - Community
Version: 29.6.2
API version: 1.55
Go version: go1.26.5
Git commit: dfc4efb
Built: Thu Jul 16 16:12:34 2026
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 29.6.2
API version: 1.55 (minimum version 1.40)
Go version: go1.26.5
Git commit: 3d80467
Built: Thu Jul 16 16:12:34 2026
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v2.2.6
GitCommit: 11ce9d5f3c68c941867e82890e93e815c1304f1b
runc:
Version: 1.3.6
GitCommit: v1.3.6-0-g491b69ba
docker-init:
Version: 0.19.0
GitCommit: de40ad0
```
PiperOrigin-RevId: 966681719
Until [#14011](https://gvisor.dev/issues/14011) is addressed, this hopefully
will reduce image_test's flakiness in asia-southeast.
Also pins dind to Docker 29 to avoid any surprises in the future.
PiperOrigin-RevId: 966634277
Add an agents category to the compatibility dashboard, along with Ollama,
OpenClaw, PicoClaw, Hermes Agent, and Claude Code.
Ollama has a test included. The *claws and Hermes reference the MAGI blog post.
No test for claude code since they require an account, and testing claude code
with a local model would likely require a beefy GPU (since claude's system
prompt is pretty big).
PiperOrigin-RevId: 958632910
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]
Implements POSIX ACLs for gVisor's overlayfs.
- Adds plumbing to keep access and default ACLs in sync with the underlying filesystems, simliar to mode
- Moves permission/filetype checking into helpers in posix_acl.go, used by both tmpfs and overlayfs
- Updates the POSIX ACL tests to be parametrized by filesystem. The existing acl test suite runs both on overlayfs and on tmpfs
This fixes journald not working for systemd user services.
- Adds a gen_compile_commands.py script to generate a `compile_commands.json` for clangd, similar to Linux's `scripts/clang-tools/gen_compile_commands.py`
- Configures the dev container to generate the database before the editor is opened
- Adds `clangd` vscode extension to the dev container (and installs `clangd` in the default image)
- Updates CONTRIBUTING.md with instructions for generating a `compile_commands.json` database when *not* using a dev container
Also switches to a less confusing link for the Dev Containers extension.
Long-term, we want to clean up our use of Bazel so that a container isn't necessary to build gVisor. As a stop-gap, let's make the out-of-box VSCode experience a little smoother by configuring a GOPACKAGESDRIVER for gopls out-of-the-box, and recommending using a dev container.
The advantage of recommending a dev container is that we can configure an on-start command to run `@io_bazel_rules_go//go` through Bazel *before* gopls starts, which installs the correct Go version in the container automatically. And in the future we can configure a `compile_commands.json` to be generated at startup for clangd (for the C++ tests).
- Updates the dev container configuration to install the Go extension and fetch the Go compiler at startup.
- Adds a settings.json that configures gopls to run a GOPACKAGESDRIVER through bazel, making LSP work for the auto-generated code.
- Updates the docs to explain how to get gopls working with or without a dev container, and marks GOPATH as "not recommended"
- Install `buildifier` in the default container, as used by the Bazel vscode extension for formatting BUILD files
Implements POSIX ACLs for gVisor's tmpfs. As a summary:
- Adds `acl` and `defaultACL` fields to tmpfs's inode
- Allows `system.posix_acl_access` and `system.posix_acl_default`
xattrs to set and retrieve POSIX ACLs
- Updates tmpfs's stat implementation to account for the ACL in
setting/retrieving a file's mode
- Updates `GenericCheckPermission` to take an optional ACL. All
non-tmpfs filesystems pass the `nil` ACL.
- Updates tmpfs's tar save-and-restore logic to store the base64-encoded
POSIX ACL xattrs in the tar header
- Adds unit tests for POSIX ACL parsing/serialization
- Adds integration tests for POSIX ACLs
- Adds a container test to verify the tmpfs tar save/restore logic with
ACLs. This required a new subcommand for `test_app` to set and fetch
xattrs in the container
The motivation for POSIX ACLs is for journald (which uses POSIX ACLs to
give non-root users access to their own `systemctl --user` services'
logs). This commit is not actually sufficient to get this working -- we
will need to plumb ACLs to overlayfs, too, which will be done in a
follow-up commit.
The implementation is very similar to the implementation in Linux,
although it is filesystem-specific rather than at the VFS layer (much
like we store `mode`, `uid`, `gid`, etc at the FS layer currently). An
optional access and default ACL is stored in each inode. If present, it
is used for permission checks and is kept in sync with the `mode`. The
`mode` is computed from the ACL when permissions are updated. If the ACL
is simple enough to be stored equivalently as a `mode`, an ACL is not
stored.
One limitation at the moment is that upon file creation, the process's
umask is masked against the creation mode regardless of the presence of
a default ACL, whereas Linux only masks against umask when *not*
inheriting from a default ACL. Fixing this would require a fair bit of
refactoring since umask isn't passed through to filesystems at all, and
is instead masked with the creation mode at the syscall layer. This is
not a security issue since the resulting permissions are always of
equal-or-greater restrictiveness to those of Linux, but is tracked in
\#13688.
Includes:
- A JSON schema for the application compatibility database (an
application can either be compatible, partially compatible, not
compatible, coming-soon, or experimentally supported)
- A web page to render the compatibility database. Each row has the name
of the application, a link to the testing methodology script, the
version we last tested with, and a badge indicating its status
- A small database including the applications whose test scripts have
been reviewed so far.
The web page includes a search bar.
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 first stage of the gVisor application compatibility test suite. This
commit adds:
- A compatibility testing helper library, containing e.g. logic to write
service config files, wait for a service to be up, and make HTTP
requests
- Initial tests for WordPress 7.0.0, Gitea 1.26.2, and Nextcloud 34.0.0.
A large library of test stacks is ready, however I am splitting them
into smaller commits in the interest of review size.
Tests first consist of a stack of images under images/compatibility/.
This is done both for consistency with the existing image tests and so
that the Dockerfiles can be modified, for example to install client or
benchmarking tools to aid with testing.
The tests themselves are written in Go and placed in test/compatibility/.
These tests are kept separate from the existing image tests for a few
reasons. First, the image tests mainly exist to find gVisor regressions;
however, a core goal of the compatibility tests is to detect when
updates to *third-party applications* cause them to stop working in
gVisor. Second, it's probably not a good idea to include the
compatibility tests in our CI/CD pipeline (at least, not yet) due to
concerns about flaky tests and/or increased iteration time. (Maybe they
should be run before a release is cut, though?)
Once the compatibility tests are merged, I'll submit the website portion
which will list the applications we have tested to be compatible. Each
entry will contain a link to its corresponding compatibility test in our
GitHub repository.
test/compatibility/README.md is included with instructions on running
the tests.
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
On Linux, mount writability checks are skipped for special devices
(char, fifo, socket, blockdevice) when opening a file with write access.
gVisor currently does not handle this correctly.
This is an issue because some systemd unit files specify
PrivateDevices=yes, one of the effects of which is to make /dev appear
read-only to the service. For these services, writing to (for example)
/dev/null gives EROFS. Apache2 in particular runs into this issue.
systemd uses this for some trivial options (ro, noswap).
I had originally wanted a proper implementation, but as far as I can
tell we have no logic to pass through reconfiguration data to underlying
filesystems, so properly supporting this will be a big change.
RemountAt(), used by MS_REMOUNT, claims to pass data to the underlying
fs, but it doesn't seem to do so. It only sets per-mount options.
For now, this behavior matches MS_REMOUNT.
Adds the infrastructure for a DynamicBytesFile to become pollable
(perhaps with select, poll, or epoll). Simply arrange for a
DynamicBytesPoller to be notified whenever the relevant file is updated
and implement PollableDynamicBytesSource on the DynamicBytesSource.
EPOLLPRI and EPOLLERR are triggered for these files, which seems to
match Linux's implementation for /proc/sys files.
The first two files to support this are hostname and domainname in
/proc/sys/kernel. This is used by systemd-journald to monitor for
hostname changes.
This frees implementations of getsockopt to no longer return EINVAL when
userspace specifies a buffer smaller than the output.
Some callers, such as resolved, pass a null buffer to probe the output
size before passing a real buffer to getsockopt. This allows those
callers to succeed.
This commit also removes EINVAL returns from netlink route sockets related to
the userspace-provided size to allow this pattern.
Previously, scmCredentials stored a *kernel.Task, from which the peer
pid could be looked up when getsockopt() was called with SO_PEERCRED.
However, if the peer had since died, the lookup would fail and the
returned pid would be 0.
Instead, we should store a snapshot of the *pid*, not the Task pointer.
The lookup should happen at open time, not at getsockopt() time.
This does mean that the returned pid may be stale, but this happens on
Linux too, so userspace should know to avoid racy behavior with the
returned PID.
Other things changed:
- Since the cred is a PID, not a TID, use the task group ID instead of
task ID
- Add a test for SO_PEERCRED across a different PID namespace
Linux requires this on a per-filesystem basis, and none of our
filesystems require it (it's mainly used for block filesystems).
source="" is a reasonable default, and our mount(2) implementation does
this as well.
The first step in implementing the new file-descriptor based mount API in
gVisor. A "filesystem creation context" is created using fsopen(). The context
is then configured using fsconfig(), and the FSCONFIG_CMD_CREATE command is
used to create a filesystem. A "mount object" can be obtained using fsmount(),
which can be operated on directly using the *at() functions or mounted onto the
real directory tree using move_mount().
The current implementation has the following limitations:
- Linux passes configuration options to filesystems on-the-fly as fsopen() and
fsconfig() are called, allowing per-parameter error handling. gVisor
currently queues up all options and passes them to the filesystem all-at-once
when FSCONFIG_CMD_CREATE occurs. Lifting this will require refactoring the
option parsing for all existing filesystems.
- Only flag and string arguments to fsconfig() are supported.
- FSCONFIG_CMD_RECONFIGURE is not supported.
- move_mount(): flags MOVE_MOUNT_SET_GROUP and MOVE_MOUNT_BENEATH are not
supported.
- The filesystem context message retrieval interface is not supported.
In the interest of review size, there is no implementation yet for
mount_setattr(2), open_tree(2), or fspick(2).
PiperOrigin-RevId: 931245256
The arg to setdomainname isn't a string, it's a byte array with a
specified length.
This fix was previously applied to sethostname(2), but not
setdomainname(2).
The first step in implementing the new file-descriptor based mount API in
gVisor. A "filesystem creation context" is created using fsopen(). The context
is then configured using fsconfig(), and the FSCONFIG_CMD_CREATE command is
used to create a filesystem. A "mount object" can be obtained using fsmount(),
which can be operated on directly using the *at() functions or mounted onto the
real directory tree using move_mount().
For compatibility reasons, the new mount API is gated behind the runtime flag
`--new-mount-api`, which is disabled by default.
The current implementation has the following limitations:
- Linux passes configuration options to filesystems on-the-fly as fsopen() and
fsconfig() are called, allowing per-parameter error handling. gVisor
currently queues up all options and passes them to the filesystem all-at-once
when FSCONFIG_CMD_CREATE occurs. Lifting this will require refactoring the
option parsing for all existing filesystems.
- Only flag and string arguments to fsconfig() are supported.
- FSCONFIG_CMD_RECONFIGURE is not supported.
- move_mount(): flags MOVE_MOUNT_SET_GROUP and MOVE_MOUNT_BENEATH are not
supported.
- The filesystem context message retrieval interface is not supported.
In the interest of review size, there is no implementation yet for
mount_setattr(2), open_tree(2), or fspick(2).
PiperOrigin-RevId: 923640824
Adds to the gofer-to-host RPC a mechanism for the gofer to request an id-mapped
mount, which is created using open_tree() and mount_setattr(). The gofer then
calls move_mount() to place the mount in the sandbox's directory hierarchy,
and calls mount_setattr() once again to configure the mount.
ID-mapped mounts are only valid if at least one UID *and* GID mapping is
specified.
PiperOrigin-RevId: 923638626
This was increased previously in cl/859296178, but I've started seeing timeouts
again (e.g. cl/921554038 and cl/908831718), so it may be time to increase this
further.
PiperOrigin-RevId: 922834323
Because we fetch from urandom under the assumption that the host urandom has
sufficient entropy, we can allow and silently ignore GRND_INSECURE for the
same reason we currently allow and silently ignore GRND_NONBLOCK.
The randomness will be more secure than what was requested, but this is fine.
PiperOrigin-RevId: 921880454
As part of supporting uid/gid-mapped mounts, we need (*Process).WithHandle,
added in Go 1.26. We can bump the Go version now to catch any issues that may
arise.
PiperOrigin-RevId: 921600692
Removes debug warnings when ENOSPC is encountered upon filesystem creation.
Documents that maxInodes == 0 means no limit in the code.
For consistency, uses maxInodes == 0 (as in, no limit) rather than
math.MaxInt64 for SB_KERNMOUNT mounts.
PiperOrigin-RevId: 917259013
Adds inode accounting to the tmpfs filesystem. Bubbles up ENOSPC if inodes run
out. Also reports inode utilization to userspace via statfs.
PiperOrigin-RevId: 916177639
Adds support for size=n% as a fraction of physical RAM in tmpfs.
Linux always prints size= in kilobytes in /proc/self/mounts, so I've also
refactored tmpfs's MountOptions() implementation to match (and print opts
in the right order).
PiperOrigin-RevId: 914993536
Since we are more interested in software support than precisely emulating Linux
v4.4, this statement in the docs is likely confusing.
(In any case, gVisor uname() is reporting 4.19 nowadays).
PiperOrigin-RevId: 910089975