gvisor Agent Skills & AI Rules

GitHub

Application Kernel for Containers

19,050 stars Go Go 1 file ยท ~10,282 tokens #containers#docker#kernel#kubernetes#linux#oci#sandbox
RAW Rules
4 Discovered Rules โ€ข ~3,544 Estimated Tokens
Quick:
Loading skill content...

AI Agent Protocol & Instructions

AGENTS.md root-instruction ~2,644 tokens
Raw
# gVisor

### What is gVisor?

gVisor is a userspace kernel used for sandboxing untrusted programs. It is
Linux-like kernel implementation in Go.

NOTE: The project uses [Bazel](https://bazel.build/) as a build system, so paths
starting with `//` refer to the repository root, and `//some/path:some_target`
refers to target `some_target` defined inside `some/path/BUILD`.

gVisor is made of multiple components:

-   The gVisor Sentry is the main component implementing a Linux-like kernel in
    Go. Its implementation is at `//pkg/sentry`.
-   Gofers are I/O proxies for the gVisor Sentry. There are multiple Gofers, but
    an implementation of one is at `//runsc/fsgofer`.
-   `runsc` is a Docker-compatible OCI-compliant container runtime that uses
    gVisor under the hood. It is useful to run Docker images in gVisor.
    Location: `//runsc`.

### Important gVisor subpackages

-   The gVisor "platform" acts as a syscall interception mechanism for sandboxed
    applications, and which is responsible for redirecting control to the gVisor
    sentry for handling the system call. There are multiple platform
    implementations; the name "platform" refers to the abstraction. Location:
    `//pkg/sentry/platform`
-   The gVisor `kernel` package implements the bulk of the kernel logic.
    Location: `//pkg/sentry/kernel`
-   The Linux kernel ABI is redefined as a Go package so that we can use it in
    the gVisor kernel. Location: `//pkg/abi`.
-   The `runsc` CLI is the main entry-point into gVisor for most usage.
-   gVisor may also be used programmatically using a subprocess-like API via
    language bindings with the `sandboxexec` API; see `//sandboxexec`.

### gVisor code conventions

See `//.gemini/styleguide.md` for a general style guide.

In the gVisor codebase, all Go packages use the same package name as the name of
their parent directory. For example:

-   The package at `//pkg/errors/linuxerr` (which is the same as the BUILD
    target `//pkg/errors/linuxerr:linuxerr`) has Go import path
    `gvisor.dev/gvisor/pkg/errors/linuxerr`.
-   The package at `//pkg/sentry/vfs` has Go import path
    `gvisor.dev/gvisor/pkg/sentry/vfs`.
-   This implies that new libraries you may create must be under their own new
    subfolder. For example, if you wish to create a library called `foo` under
    an existing directory `//pkg/bar`, you should create the directory
    `//pkg/bar/foo` and then create a file `//pkg/bar/foo/foo.go` within it. The
    `BUILD` file at `//pkg/bar/foo/BUILD` would contain the `go_library` rule
    with name `foo`, and the `package` line within `//pkg/bar/foo/foo.go` would
    be `package foo`. The import statement for this package in other Go
    libraries would be `gvisor.dev/gvisor/pkg/bar/foo`, and the dependency
    target would be `//pkg/bar/foo`. Other Go source files within
    `//pkg/bar/foo` generally also belong to the same Go package, though it is
    also acceptable to use the `foo_test` package name for test files in the
    same `//pkg/bar/foo` directory, if having a separate package name is
    desirable.
-   gVisor's Bazel rules are wrappers over the usual ones, especially for
    `go_library`, `go_binary`, and `go_test`. They should be imported into
    `BUILD` files from `//tools:defs.bzl`, e.g. `load("//tools:defs.bzl",
    "go_library")` for the `go_library` wrapper. These wrapper rules create
    auto-generated Go source files that are added to the source code of each Go
    package, enabling code generation for Go code that gets injected into every
    package, such as automated serialization. You generally do not need to
    inspect these autogenerated Go source files, but be aware that they exist,
    and that what you see in the repository is not the entire picture that the
    Go compiler actually sees.
-   When writing tests that need to read external files as input, you should use
    the `testutil.FindFile` function defined in `//pkg/test/testutil` with
    import path `gvisor.dev/gvisor/pkg/test/testutil`. It takes in a path as
    argument, which is rooted from the `//` directory. For example, to access
    file `//foo/bar/baz.txt`, you would call
    `testutil.FindFile("foo/bar/baz.txt")`. Every external file that you expect
    to be able to find using `testutil.FindFile` must also be declared as a
    `data` dependency in the `BUILD` target of the `go_test` target you are
    editing. For example, to access file `//foo/bar/baz.txt`, the `go_test`
    BUILD rule would need to have `data = ["//foo/bar:baz.txt"]`. If you want an
    example, look at existing usages of this function to understand how it
    works, e.g. `dumpfilter_test.go` in `//runsc/boot/filter/dumpfilter`.
-   Despite being a bazel project, gVisor uses a Docker-based wrapper over bazel
    using `make`. The `Makefile` defines wrapper rules over `bazel` subcommands,
    which run these commands inside an automatically-managed Docker container.
    This container is useful to smooth over Bazel quirks and version differences
    across machines. For example, building a target is `make build
    TARGETS=//path/to:target`, and running a test is `make test
    TARGETS=//path/to:some_test`.
-   Comments must describe the code as it is for the future codebase readers,
    not for present-time PR reviewers. A comment that talks about a bug that the
    PR at hand fixes is counter-productive, because it leaves behind irrelevant
    historical context that future readers of the codebase should no longer have
    to worry about.
-   Function/struct/field comments should generally not refer to their callers
    (e.g. "Used by", "Useful for"). If this is not already clear from the
    function name or context, then the function name and/or context is the
    problem, and the comment is a band-aid.
-   Prose (such as comments, documentation, other markdown files) should mostly
    follow ASD-STE100 Simplified Technical English. Some liberties are expected
    (and welcome in some contexts, such as website/blog post contents), but
    technical content should be crisp, clear, and to-the-point.
-   gVisor is packaged as a fileset at `//:release`, and any consumers of this
    must treat this as an opaque, all-or-nothing set of files to install or set
    up. With narrow exceptions, they should not enumerate the set of files
    within.

### General approach to resolving gVisor issues

#### Modifying gVisor kernel behavior

Use the `gvisor-kernel-development` skill.

#### Security first

All changes are reviewed for security. gVisor's design and architecture ensures
that a Sentry compromise, however unlikely, is still tightly contained.
Nonetheless, any changes to the Sentry are very security-sensitive and must be
reviewed carefully to avoid introducing new escalation vectors. See
`SECURITY.md` for various aspects of gVisor security.

#### Compatibility in practice

gVisor aims to match broad Linux-like behavior, but this is a moving target and
some incompatibilities matter more than others in practice. If there exists no
popular real-world application that runs into the compatibility problem that a
PR is addressing, the PR review will be de-prioritized against those that do
have popular real-world applications.

The pecking order, from most important to least, with compatibility code:

-   `COMPATIBILITY:REGRESSION-GVISOR`: Regressions in real-world application
    compatibility of a previously-supported application, due to past changes in
    gVisor
-   `COMPATIBILITY:REGRESSION-APP`: Regressions in real-world application
    compatibility of a previously-supported application, due to changes/updates
    by the application
-   `COMPATIBILITY:UPCOMING-KERNEL`: Incompatibilities not yet encountered, but
    known to later be encountered due to an upcoming change in the Linux kernel.
-   `COMPATIBILITY:NEW-APP`: Incompatibilities encountered in real-world
    applications that never worked in gVisor before, in their default
    configuration/use-case.
-   `COMPATIBILITY:NEW-APP-CONFIG`: Incompatibilities encountered in real-world
    applications that never worked in gVisor before, in a specific non-default
    configuration/use-case.
-   `COMPATIBILITY:PREVENTIVE-APP`: Syscall-test-only change that verifies a
    piece of **working** gVisor compatibility that isn't yet covered by syscall
    tests, which is known to be relied upon by a real-world application.
-   `COMPATIBILITY:UPCOMING-APP`: Incompatibilities not yet encountered, but
    known to later be encountered due to an upcoming change in an application
    that currently works in gVisor.
-   `COMPATIBILITY:SYNTHETIC`: Incompatibilities exercisable only via syscall
    tests, which no known real-world application encounters.

#### Performance sensitivity

As a kernel, gVisor performance matters almost as much as security. As such, any
change that may impact performance is required to come with benchmark
measurements to measure its benefit and to avoid regressions.

The following code is particularly performance-sensitive:

-   The system call hot path: entry and dispatch in `pkg/sentry/kernel`
    (`task_run.go`, `task_syscall.go`), the handlers in
    `pkg/sentry/syscalls/linux`, and the layers that copy data to and from
    application memory (`pkg/usermem`, `pkg/safemem`, `pkg/safecopy`,
    `pkg/marshal`).
-   Platform code (`pkg/sentry/platform`, `pkg/ring0`).
-   Serialization code (`pkg/state`).
-   Sandbox startup (`runsc/boot`, `runsc/container`, `runsc/sandbox`).
-   Netstack (`pkg/tcpip`).
-   Checkpoint/restore (`pkg/state`, `pkg/sentry/state`).
-   File I/O (`pkg/sentry/vfs`, `pkg/sentry/fsimpl`).
-   Memory management (`pkg/sentry/mm`, `pkg/sentry/pgalloc`).
-   Inter-process communication with the gofer (`pkg/lisafs`, `runsc/fsgofer`).
-   Go `init()` functions that run on every binary startup.

Load the `gvisor-performance` skill whenever any of these paths show up, or when
a change has any possibility of performance implications. Test-only changes do
not have performance implications.

## Git / GitHub / PR Guidelines

Before sending PRs, check the following:

-   Compatibility fixes must come with a compatibility code (see "Compatibility
    in practice" section), along with an explanation for this code.
-   Syscall behavior must be verified to match Linux behavior by way of syscall
    tests, not Go tests.
-   Everything must build; use `make build TARGETS=...` building affected paths.
-   Relevant tests must pass; use `make test TARGETS=...` or `make syscall-tests
    TARGETS=...` as appropriate.
-   All PRs must pass `make lint` and `make lint-cc`.
-   When benchmarks are required, they must come with statistically-significant
    figures. See section on performance changes.
-   Website changes should come with before/after screenshots (use `make
    website-server` to start an HTTP server serving the site locally).
-   Test-only changes that improve stability/flakiness are very much welcome.