Skip to content

[release-1.0] Cherry-pick #3580: Restrict actor capabilities.add and make mounts nodev - #3611

Merged
Benjamin Elder (BenTheElder) merged 1 commit into
agent-substrate:release-1.0from
dberkov:release-1.0-cherry-pick-3580
Nov 4, 2026
Merged

Benjamin Elder (BenTheElder) merged 1 commit into
agent-substrate:release-1.0from
dberkov:release-1.0-cherry-pick-3580

Conversation

@dberkov

Copy link
Copy Markdown
Collaborator

Cherry-pick of #3580 onto release-1.0 (git cherry-pick -x of the squash commit), it applied cleanly with no changes. Fixes #3579 for the release branch.

securityContext.capabilities.add is restricted to a 12-capability allowlist at admission in both ateapi and atelet; drop still accepts any name. Volume bind mounts and gVisor system mounts gain nodev, and the microVM guest sets net.ipv4.ping_group_range so unprivileged ping keeps working without NET_RAW.

AI use: AI-assisted. Clean pick.

This carries the same breaking changes as #3580: templates adding MKNOD, SYS_ADMIN, SYS_RAWIO or anything else outside the allowlist are now rejected, and gVisor MEMORY snapshots taken before the upgrade no longer restore. The snapshot break is already present in rc.2 via #3533, so it adds no new upgrade step; see #3580 for the upgrade notes.

  • Tests pass
  • Docs updated

🤖 Generated with Claude Code

…e#3580)

Fixes [agent-substrate#3579](agent-substrate#3579)

### Summary

Restricts `securityContext.capabilities.add` to a hardened allowlist of
12 Linux capabilities and blocks dangerous capabilities such as `MKNOD`,
`SYS_ADMIN`, and `SYS_RAWIO` before 1.0.

In microVM sandboxes, granting `MKNOD` to a container running as root
allows it to create block device nodes matching the guest's
`virtio-pmem` root disk and directly write to the guest filesystem.
Other capabilities like `SYS_ADMIN` and `SYS_RAWIO` expose dangerous
guest kernel attack surface.

### Changes

* **Capability Allowlist:** `securityContext.capabilities.add` now only
permits 12 capabilities required for package installs, non-root user
switches, and standard container workflows:
  * `AUDIT_WRITE`
  * `CHOWN`
  * `DAC_OVERRIDE`
  * `FOWNER`
  * `FSETID`
  * `KILL`
  * `NET_BIND_SERVICE`
  * `SETFCAP`
  * `SETGID`
  * `SETPCAP`
  * `SETUID`
  * `SYS_CHROOT`
* **Admission Enforcement:** `ateapi` and `atelet` reject actor template
creations and updates specifying capabilities outside this allowlist.
* **Drop Unrestricted:** `securityContext.capabilities.drop` continues
to accept any capability name.
* **MicroVM Hardening:**
* Volume bind mounts are now mounted with `nodev`, and the microVM guest
mounts the virtio-fs share with `nodev` (covering automounted submounts
and rootfs). `ShapeGVisor` strips `nodev`, keeping gVisor specs
identical and preserving checkpoint/restore compatibility.
* MicroVM guest sysctl `net.ipv4.ping_group_range = "0 2147483647"` is
configured so standard unprivileged `ping` continues to work without
requiring `NET_RAW`.
* **Documentation & Schemas:** Updated `api-guide.md`,
`sandbox-classes.md`, and regenerated protobuf bindings (`ateapi.pb.go`,
`atelet.pb.go`).

### Breaking change: gVisor `MEMORY` snapshots taken before this release
won't restore

gVisor now gets `nodev` on volume and system mounts (`/proc`,
`/dev/shm`, `/sys`, `/tmp`), matching microVM. runsc applies it to the
host bind mount. `runsc restore` rejects a checkpoint whose mounts
differ from the new spec (`"Mounts" does not match across checkpoint
restore`), so gVisor `MEMORY` snapshots taken before the upgrade can't
be restored. rc.2 already breaks these snapshots with
[agent-substrate#3533](agent-substrate#3533) (tmpfs
`/dev/shm` and `/tmp`), so this adds no new upgrade step on top of that.
MicroVM actors are unaffected.

**What breaks:**

- Suspended gVisor actors whose latest snapshot is `MEMORY` fidelity
(the default) move to `ACTOR_STATE_CRASHED` on `ResumeActor`.
- New actors from gVisor templates created before the upgrade crash on
first resume, because the template's golden snapshot is an old `MEMORY`
checkpoint.

**Upgrade steps:**

1. **Before upgrading,** resume any suspended gVisor actor whose
in-memory state you need, and save that state to durable storage or let
its work finish.
2. **Re-create gVisor templates.** `ActorTemplate` is immutable, so
create a new template (e.g. `my-template-v2`), or delete and re-create
it, to build a new golden snapshot. Point clients at the new template.
3. **Replace crashed actors.** `RevertActor` won't help: it reverts to
the same pre-upgrade checkpoint, which crashes again. `UpdateActor
--template` won't either, because resume restores the actor's own
snapshot. Delete the actor and create it again from the new template.
Its in-memory state and its snapshot's rootfs and volume contents are
lost.

### Testing

* **Unit Tests:** Updated resource validation tests, parity tests, and
microVM spec tests (`go test ./...` passes in container).
* **Live GKE Testing (`sgke-rc1`):**
  * Verified template rejection when adding `MKNOD` or `SYS_ADMIN`.
* Verified unprivileged ICMP `ping` works in microVM guests without
`NET_RAW`.
  * Verified that pre-existing gVisor actor snapshots restore cleanly.
* **e2e Probe Coverage:**
  * Verified inside the guest that `mknod` fails with `EPERM`.
* Verified that unprivileged users can open `SOCK_DGRAM`/`IPPROTO_ICMP`
sockets across both runtimes.

Thanks to [Fabiano Fidêncio (@fidencio)](https://github.com/fidencio)
for the report on MKNOD that led us to make this change.

---------

Signed-off-by: Greg Castle <[email protected]>
(cherry picked from commit 17fa858)
Signed-off-by: dberkov <[email protected]>
@BenTheElder
Benjamin Elder (BenTheElder) merged commit e59281c into agent-substrate:release-1.0 Nov 4, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants