Skip to content

fix(envd): run the command when oom_score_adj cannot be set - #3820

Open
luyuzhe111 wants to merge 1 commit into
e2b-dev:mainfrom
luyuzhe111:envd-best-effort-oom-score-adj
Open

luyuzhe111 wants to merge 1 commit into
e2b-dev:mainfrom
luyuzhe111:envd-best-effort-oom-score-adj

Conversation

@luyuzhe111

@luyuzhe111 luyuzhe111 commented Nov 12, 2026 •

Copy link
Copy Markdown

Summary

envd wraps every process in /bin/sh -c 'echo 100 > /proc/$$/oom_score_adj && exec ... "$@"'. Lowering oom_score_adj below its current value needs CAP_SYS_RESOURCE. So in a container that starts with a score above 100 and has no CAP_SYS_RESOURCE, the write fails with EACCES (dash prints --: 1: echo: echo: I/O error), the && skips the exec, and no command can run at all.

We hit this running envd in Amazon Bedrock AgentCore Runtime containers. There, one platform generation starts the container at oom_score_adj 1000 with CapBnd: 00000000a82425fb (no CAP_SYS_RESOURCE), so every write below 1000 is refused, even as root. The other generation starts at -998, and envd works there.

This PR makes the write best effort, like the ionice/nice helpers in the same wrapper:

echo 100 2>/dev/null > /proc/$$/oom_score_adj; exec ... "$@"

Where the write succeeds (Firecracker, or any container that is allowed to set 100), behavior is unchanged. Where it is refused, the command runs with the score it inherited from envd instead of failing. The 2>/dev/null comes before the target so that a failed open does not print to the user's stderr either.

Testing

  • New TestOomWrapper runs the wrapper through /bin/sh:
    • It checks that a permitted score is applied.
    • It checks that the command still runs, keeps its inherited score, and prints nothing extra when the write is refused. As root, which is how CI runs envd tests, the child runs as nobody so it lacks CAP_SYS_RESOURCE.
  • Against the old && script, the second case fails with the I/O error above.
  • Both cases pass in debian:bookworm-slim (dash) and alpine:3.20 (busybox ash), each in five setups: as root with default capabilities, with CAP_SYS_RESOURCE, with CAP_SYS_RESOURCE and --oom-score-adj -998, and with --oom-score-adj 1000 and no CAP_SYS_RESOURCE; and as nobody with --oom-score-adj 1000.
  • go test -race ./internal/services/process/..., go vet, and golangci-lint run / fmt all pass.

The process wrapper chained exec to the oom_score_adj write with &&.
Lowering oom_score_adj needs CAP_SYS_RESOURCE, so in a container that
starts above 100 without that capability every write fails with EACCES
(dash: "echo: I/O error") and no command can run. Make the write best
effort, like the ionice/nice helpers, and keep its error off the
user's stderr.
@cla-bot

cla-bot Bot commented Nov 12, 2026

Copy link
Copy Markdown

We require contributors to sign our Contributor License Agreement, and we don't have @luyuzhe111 on file. You can sign our CLA at https://e2b.dev/docs/cla . Once you've signed, post a comment here that says '@cla-bot check'

@luyuzhe111

Copy link
Copy Markdown
Author

@cla-bot check

@cla-bot cla-bot Bot added the cla-signed label Nov 12, 2026
@cla-bot

cla-bot Bot commented Nov 12, 2026

Copy link
Copy Markdown

The cla-bot has been summoned, and re-checked this pull request!

This branch has not been deployed

No deployments
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.

1 participant