Skip to content

microvm: forward sysctls and lift the guest's privileged-port limit to match gVisor - #1904

Merged
Benjamin Elder (BenTheElder) merged 5 commits into
agent-substrate:mainfrom
dims:pr/microvm-sysctls
Oct 27, 2026
Merged

Benjamin Elder (BenTheElder) merged 5 commits into
agent-substrate:mainfrom
dims:pr/microvm-sysctls

Conversation

@dims

@dims Davanum Srinivas (dims) commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

A micro-VM container that drops NET_BIND_SERVICE could not bind a port below 1024; the same container on gVisor could, since its network stack has no privileged-port limit.

The kata agent now receives the spec's sysctls, and ShapeMicroVM sets net.ipv4.ip_unprivileged_port_start=0, so both runtimes behave the same. Neither sets no_new_privileges; gVisor runs with --allow-suid since #2361, so setuid binaries work on both.

The capabilities e2e suite gains a drop-ALL template whose probe listens on port 80, and the probe reports NoNewPrivs, asserted off on both lanes.

  • Tests pass: go test -race ./internal/ocispec/..., GOOS=linux go vet on kata and ocispec, go vet ./internal/e2e/...; e2e on both lanes in CI.
  • Appropriate changes to documentation are included in the PR: docs/api-guide.md.

@dims
Davanum Srinivas (dims) marked this pull request as ready for review September 25, 2026 23:52
@dims
Davanum Srinivas (dims) marked this pull request as draft September 26, 2026 02:19
@dims Davanum Srinivas (dims) changed the title microvm: forward Linux.Sysctl to the kata agent and allow low ports microvm: parity with gVisor for sysctls, low ports and no_new_privileges Sep 26, 2026
@dims
Davanum Srinivas (dims) force-pushed the pr/microvm-sysctls branch 3 times, most recently from 3eb0b33 to 4c25c22 Compare September 27, 2026 02:00
@dims
Davanum Srinivas (dims) marked this pull request as ready for review September 27, 2026 02:25
@dims

Copy link
Copy Markdown
Collaborator Author

@BenTheElder

Copy link
Copy Markdown
Collaborator

Both stay out of Build: runsc restore compares Sysctl and Process with the checkpoint-time spec, so a shared default would break restores of older gVisor snapshots

we have no back compat right now and aggressively prefer the approach that is more correct / maintainable long-term than accruing halfway compat attempts

@dims

Copy link
Copy Markdown
Collaborator Author

thanks Tim Hockin (@thockin) Benjamin Elder (@BenTheElder) i've removed backward compat stuff.

@bowei Bowei Du (bowei) added area/security Security related issue/pr kind/bug Something isn't working / bugfixes labels Sep 30, 2026

@mayawang Maya Wang (mayawang) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good. One question on where these two settings live, following Ben's note above.

Comment thread internal/ocispec/microvm.go Resolved
@dims Davanum Srinivas (dims) changed the title microvm: parity with gVisor for sysctls, low ports and no_new_privileges microvm: forward sysctls, allow low ports; set no_new_privileges on every container Oct 1, 2026
Comment thread internal/ocispec/ocispec.go Resolved
Comment thread internal/ocispec/microvm.go Resolved
Comment thread docs/upgrade.md Resolved
Comment thread docs/api-guide.md Resolved
Comment thread docs/api-guide.md Resolved
@dims
Davanum Srinivas (dims) force-pushed the pr/microvm-sysctls branch 4 times, most recently from fda5193 to 8bfff79 Compare October 17, 2026 11:59
@dims Davanum Srinivas (dims) changed the title microvm: forward sysctls, allow low ports; set no_new_privileges on every container microvm: forward sysctls and lift the guest's privileged-port limit to match gVisor Oct 17, 2026
@dims

Copy link
Copy Markdown
Collaborator Author

thanks Benjamin Elder (@BenTheElder) fixed this up as #2361 merged

@dims

Copy link
Copy Markdown
Collaborator Author

So with this PR, OpenShell runs in micro-VM actors without any workaround. Would be great to see it merged.

w00t! thanks for confirming!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[explicitly tracking for M3 compat/security fix]

@dims
Davanum Srinivas (dims) force-pushed the pr/microvm-sysctls branch 2 times, most recently from 2bf9ea1 to 21d9bf2 Compare October 23, 2026 14:59
@dims

Copy link
Copy Markdown
Collaborator Author

Benjamin Elder (@BenTheElder) fixed the comments. thanks!

The agent honors sysctls, and net.* keys need no network namespace of
their own, which is what ateom-microvm produces.

Signed-off-by: Davanum Srinivas <davanum@gmail.com>
Set net.ipv4.ip_unprivileged_port_start=0 in ShapeMicroVM. gVisor has no
privileged-port check and runsc ignores this sysctl, so only the guest
kernel needs it.

Signed-off-by: Davanum Srinivas <davanum@gmail.com>
The probe listens on port 80, so a caps-none template proves the bind on
both runtimes. The probe also reports NoNewPrivs; neither runtime sets
it, and gVisor runs with --allow-suid.

Signed-off-by: Davanum Srinivas <davanum@gmail.com>
The caps-exact note claimed the probe could not come up without
NET_BIND_SERVICE. Low ports bind without it on both runtimes now, so
the proof is caps-none's golden bake. Move the note there and update
the fixture header and the test comments for the third template.

Signed-off-by: Davanum Srinivas <davanum@gmail.com>
The caps-exact template said what it grants three times: the config, its
header and an inline comment. Keep the names in the config and give each
template one header that says why.

Signed-off-by: Davanum Srinivas <davanum@gmail.com>
@thockin Tim Hockin (thockin) added the prio/P0 Highest priority / required for next milestone label Oct 27, 2026
@BenTheElder
Benjamin Elder (BenTheElder) added this pull request to the merge queue Oct 27, 2026
Merged via the queue into agent-substrate:main with commit 4150e4b Oct 27, 2026
5 checks passed
Greg Castle (destijl) pushed a commit to destijl/substrate that referenced this pull request Oct 29, 2026
…s kept (agent-substrate#2392)

Containers ignored the image's `USER` and `WORKDIR` and ran as root in
`/`, and atelet's unpack dropped the file owners image layers record. So
an image that hands a directory to its user, such as jupyter's
`/home/jovyan`, didn't work as built.

- atelet applies each tar entry's uid/gid and keeps setuid, setgid and
sticky bits. It adds `CHOWN`, `FOWNER` and `FSETID` to its
`DAC_OVERRIDE`. The image cache layout moves to version 3.
- The process runs as the image's `USER`, resolved as Docker does
against the image's own `/etc/passwd` and `/etc/group`, and starts in
its `WORKDIR` (default `/`).
- The jupyter demo runs as jovyan and drops `DAC_OVERRIDE` and
`--allow-root`.

The `USER` and `WORKDIR` commits are @dims's from agent-substrate#1918, kept as
written. This PR supersedes agent-substrate#1918.

Fixes agent-substrate#2036

#### Breaking change

Please add the `breaking-change` label.

- After an upgrade or rollback, atelet refuses the existing image cache.
Delete `/var/lib/ate/image-cache` on each node once no actor runs on it,
as atelet's error says. After an upgrade, a node reboot also works.
- A custom atelet securityContext needs `CHOWN`, `DAC_OVERRIDE`,
`FOWNER` and `FSETID`.
- Images with a `USER` stop running as root, and images with a `WORKDIR`
stop starting in `/`. A non-root `USER` is expected to have no effective
capabilities, so `securityContext.capabilities.add` no longer helps it.
This is checked under runc and in the gVisor source, not yet inside a
gVisor or microVM sandbox.
- gVisor snapshots of such images don't restore, because `runsc restore`
checks each container's user and working directory. Recreate those
templates. MicroVM snapshots resume as they were.
- Files an earlier run wrote as root into a durable dir stay root-owned.

Tested: `go test -race` on atelet, imagecache, ocispec, tarutil, kata
and the probe fixture, on macOS and on Linux as non-root, and imagecache
with `-count=3 -shuffle=on`. The root-only imagecache and tarutil tests
pass as root on a privileged Linux container. `hack/verify-all.sh`
passes. The jupyter image serves `/api` under Docker as 1000:100 with
every capability dropped. @dims ran the jupyter demo and a non-root node
image as their users on kind, on both runtimes, before agent-substrate#1904 merged; on
microVM uid 1000 couldn't bind :80 then. A new imagefs e2e starts an
actor from a probe image with `USER nonroot:nonroot` and `WORKDIR
/home/nonroot`. It checks uid and gid 65532, no supplementary group
besides 65532, no effective capabilities, the working directory, and
that the user can create a file there. CI runs it on gVisor and on
microVM. At this head nothing ran in a gVisor or microVM sandbox yet:
not the jupyter demo and not the imagefs e2e.

- [ ] Tests pass
- [x] Docs updated

---------

Signed-off-by: Anish Ramasekar <anish.ramasekar@gmail.com>
Signed-off-by: Davanum Srinivas <davanum@gmail.com>
Co-authored-by: Davanum Srinivas <davanum@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/microVM area/security Security related issue/pr kind/bug Something isn't working / bugfixes milestone-ack prio/P0 Highest priority / required for next milestone

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants