Skip to content

Keep a namespace box's environment off every command line - #163

Merged
M3gA-Mind merged 5 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/sr024b-namespace-env-off-argv
Nov 12, 2026
Merged

M3gA-Mind merged 5 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/sr024b-namespace-env-off-argv

Conversation

@M3gA-Mind

Copy link
Copy Markdown
Collaborator

Summary

A namespace box (tinybox-linux NamespaceSandbox) passed each environment variable to bwrap as --setenv KEY VALUE on its argv. /proc/<pid>/cmdline shows that to every process of the same user. On an SSH host, the whole argv also travels inside the remote shell command, so the values sit on the local ssh command line and on the remote shell's.

The --setenv list now reaches bwrap on its stdin, NUL-separated, through bwrap --args 0.

  • Every host already forwards a command's stdin: the local host pipes it, and the SSH host carries it to the far side.
  • Namespace exec didn't forward the caller's stdin before this change, so the slot was free.
  • No value appears on any command line, locally or on an SSH host, and no upload or temp file is needed.
  • A key or value holding a NUL is refused before anything runs, since it would end the entry early and let the rest be read as bwrap options.

This is the namespace-box counterpart of #155, which does the same for the 2.1 native resource jail.

Related issue

None filed. Found while reviewing #155.

API or behavior changes

  • No API change.
  • A namespace command now always gets an empty stdin, as before. If namespace exec ever forwards the caller's stdin, the environment must move to another descriptor; that's documented at args::environment.
  • A NUL in an environment entry is now refused with Error::Backend. Before, it failed at spawn.

Validation

On our Linux CI runner (bubblewrap 0.9.0), at 7a3e783ca8. The head differs only by applying cargo fmt's patch:

  • cargo clippy --all-targets --all-features -- -D warnings: 0 errors, same as main. cargo build and cargo doc: ok.
  • cargo test -p tinybox-linux sandbox: 42 passed.
  • TINYBOX_LIVE_NAMESPACES=1 cargo test -p tinybox-linux --test live_namespaces: 15 passed, all of them run, none returned early.
  • cargo test --workspace --no-fail-fast: 1578 passed, 0 failed, with no failures unique to this branch.
  • Red control: putting the --setenv loop back on the argv fails both the unit test (the argv carries --setenv) and the live test (the value appears on the bwrap command line).

Tests

  • the_environment_is_cleared_and_then_rebuilt: the argv has --clearenv and --args 0 and no value; the stdin holds --setenv FROM_BOX 1 --setenv FROM_COMMAND 2, the box's first.
  • without_an_environment_bwrap_reads_no_arguments_from_stdin.
  • a_nul_in_an_environment_value_is_refused_before_anything_runs.
  • Live: live_an_environment_value_is_on_no_command_line_while_the_box_runs scans every /proc/*/cmdline while a box command runs, then checks that the command still received the value. The existing live_the_callers_environment_does_not_leak_in still passes.

Documentation

Rustdoc on args::environment and the comment in bwrap().

Checklist

  • The change is focused on one logical change
  • No new #[allow(...)], #[ignore], or relaxed lints
  • No secrets, tokens, or .env contents in the diff or the description

Namespace boxes passed each variable to bwrap as --setenv KEY VALUE on its
argv, which /proc/<pid>/cmdline shows to every process of the user, and which
an SSH host also carries inside the remote shell command. The --setenv list now
reaches bwrap on its stdin (bwrap --args 0), which every host forwards and
namespace exec otherwise leaves empty. A NUL in a key or value is refused
before anything runs.
@coderabbitai

coderabbitai Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3878b2a4-b094-4904-9925-42ad89e67413
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@tinysweeper

tinysweeper Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Reviewed head: cf2af96744e1179cd229d76dbb0eb28e74acf2e0

Findings

No active actionable findings.

Resolved this pass

  • Preserve the caller's stdin when building the bwrap request
  • Preserve the caller's stdin when building the bwrap request
  • Preserve the caller's stdin when building the bwrap request
  • Preserve the caller's stdin when building the bwrap request

Verdict: Ready for maintainer review · Priority: none
Coverage: Reviewed 4 of 4 files.

Diagnostics and supporting details

Full summary

Pull request purpose (title): Keep a namespace box's environment off every command line. The change stops `NamespaceSandbox` from passing environment variables to bwrap as `--setenv KEY VALUE` on its argv, which `/proc/<pid>/cmdline` exposes to every process of the same user and which, on an SSH host, also travels inside the remote shell command. The argv instead carries `--clearenv` plus `--args 0` only when there is something to set, and bwrap reads NUL-terminated `--setenv` records from stdin, box environment first and the request's on top, matching other backends. A key or value containing a NUL is refused with `Error::Backend` before anything spawns, since a NUL would end an entry early and let the remainder be parsed as further bwrap options. Because the environment payload occupies the command's stdin, `exec` branches on the environment payload and the caller's `request.stdin`: both present is refused with `Error::Backend` rather than dropping one, a caller stdin with no environment is forwarded through, and neither case leaves the request untouched. The commits lane answered with no sensitive content in the committed files. The latest-push-delta section is separately labeled and unavailable: review state has the prior reviewed head and rendered evidence but no trusted base-to-head diff comparison, so no push delta is described.

Review snapshot

Change surface Files Review signal Count
Production 2 Active findings 0
Tests 2 Noted findings 0
Documentation 0 Resolved findings 4
Configuration 0 Pending checks/questions 0

Completeness: Complete
Test assessment: No supported feature-to-test mapping was available; this does not mean tests are absent or passed.

What changed

Environment variables no longer travel to bwrap on its argv: `bwrap` emits `--clearenv` and, only when the box or request holds variables, `--args 0`, while the new `args::environment` helper serializes the entries as NUL-terminated `--setenv` records with the box's environment first, returning `None` when there is nothing to set and rejecting NUL-containing keys or values with `Error::Backend` before the host is invoked. `NamespaceSandbox`'s `exec` builds the fresh `ExecRequest` from the argv and matches on the pair of the environment payload and `request.stdin`: both present is refused with `Error::Backend`, an environment alone is attached via `with_stdin`, a caller stdin alone is forwarded via `with_stdin`, and neither leaves the request unchanged. The helper's rustdoc documents that the stdin slot is consumed, that caller stdin is only forwarded to a command with no environment, and that a command with both is refused. No API change is introduced; a NUL entry now fails at validation rather than at spawn.

Features

  • Modified — Environment delivered to bwrap on stdin via `--args 0` instead of argv: Environment values no longer appear on any command line, locally or over SSH, while bwrap still receives them; `--args 0` is added only when there is something to set. (crates/tinybox-linux/src/sandbox/args.rs pub(super) fn bwrap(spec: &BoxSpec, request: &ExecRequest) -> Result<Vec<String>, crates/tinybox-linux/src/sandbox/mod.rs impl Sandbox for NamespaceSandbox {)
  • Added — NUL-containing environment entries refused before spawn: A NUL that would terminate an entry early and let the remainder be parsed as bwrap options now fails with `Error::Backend` before any command runs, rather than failing at spawn. (crates/tinybox-linux/src/sandbox/args.rs pub(super) fn bwrap(spec: &BoxSpec, request: &ExecRequest) -> Result<Vec<String>)
  • Modified — Caller stdin forwarded when there is no environment, and refused when combined with one: `NamespaceSandbox`'s `exec` attaches the environment payload or the caller's stdin via `with_stdin` and refuses a command that has both with `Error::Backend` instead of dropping one, so caller stdin with no environment now reaches the command. (crates/tinybox-linux/src/sandbox/mod.rs impl Sandbox for NamespaceSandbox {, crates/tinybox-linux/src/sandbox/args.rs pub(super) fn bwrap(spec: &BoxSpec, request: &ExecRequest) -> Result<Vec<String>)

Tests

No supported feature-to-test mapping was produced. Test execution is not inferred.

Before merge

None.

Agent review details

critique

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The critique lane answered with no findings at this head, describing the args.rs side as sound and noting the earlier caller-stdin concern is addressed by the explicit refusal plus the `(None, Some(stdin))` branch, with the stdin channel being genuinely unavailable when an environment is set and reported as an error rather than mishandled.
  • Lane summary: The change moves the sandbox environment off argv into a NUL-separated stream on bwrap's stdin, and `mod.rs` (already present) refuses a request that supplies both an environment and stdin rather than silently dropping one. The earlier concern — losing the caller's stdin — was addressed by that explicit refusal plus the `(None, Some(stdin))` branch, and the NUL guard in `environment` keeps a crafted key or value from injecting extra bwrap options. The args.rs side is sound; the remaining caveat is that the stdin channel is genuinely unavailable when an environment is set, which the code reports as an error rather than mishandling. _The code index is behind this pull request (indexed at `2459fb4d48fc`), so retrieved context may be out of date._

security

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The security lane answered with no findings, noting the environment moves off argv into NUL-terminated `--setenv` records read through `bwrap --args 0`, the NUL-byte rejection prevents early termination of an entry, and the caller refuses an exec with both an environment and explicit stdin rather than silently dropping either.
  • Lane summary: The change moves the command environment off argv into NUL-terminated `--setenv` records read through `bwrap --args 0`, rejecting NUL bytes in keys and values so an entry cannot be terminated early and the remainder parsed as bwrap options; the caller in `mod.rs` refuses an exec that has both an environment and explicit stdin rather than silently dropping either. The earlier stdin finding is resolved by that explicit refusal and its tests. Nothing further to report. _The code index is behind this pull request (indexed at `2459fb4d48fc`), so retrieved context may be out of date._

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The environment now reaches bwrap via `--args 0` on stdin instead of `--setenv` on the command line, and a command asking for both stdin and an environment is refused rather than silently losing one; the new unit tests pin the exact stdin bytes, the no-environment case, stdin forwarding, the refusal, and the NUL rejection, and the gated live test checks `/proc/*/cmdline` while the box runs. The earlier disputed finding about dropping the caller's stdin is addressed by the `(None, Some(stdin))` arm and its test, so I am not re-raising it. I found no blocking defect in this revision. _The code index is behind this pull request (indexed at `2459fb4d48fc`), so retrieved context may be out of date._

commits

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The commits lane answered and reported no sensitive content in the committed files.
  • Lane summary: No sensitive content in committed files. (1 earlier finding(s) still open) _The code index is behind this pull request (indexed at `2459fb4d48fc`), so retrieved context may be out of date._

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The description lane answered with no findings, confirming the change moves the environment onto bwrap's stdin via `--args 0` with NUL entries refused up front and tests covering the empty-environment, env-only, stdin-only, and both-together paths, and that the earlier caller-stdin concern is addressed by the explicit forwarding branch.
  • Lane summary: The change moves the namespace box's environment off bwrap's argv onto its stdin via `--args 0`, with NUL entries refused up front and tests covering the empty-environment, env-only, stdin-only and both-together paths. The description matches the diff, and the earlier disputed concern about losing the caller's stdin is addressed by the explicit branch that forwards stdin when there is no environment; I found nothing further to report. _The code index is behind this pull request (indexed at `2459fb4d48fc`), so retrieved context may be out of date._
Evidence and run details
  • Models: ladder/vectors-oai3, deepseek-v4.1-flash
  • Spend: $0.002348
  • Tokens: 229536 input · 5312 output · 72448 cached · 465 embedding
  • Updated: 2026-11-12T09:03:58Z
Head State Pass summary
9ef9dc2b025d ready for maintainer review 0 active finding(s), 0 resolved finding(s) (at 2026-11-11T12:51:44Z)
bcd5971318c4 changes requested 1 active finding(s), 0 resolved finding(s) (at 2026-11-11T14:16:19Z)
bb532d74df65 changes requested 0 active finding(s), 0 resolved finding(s) (at 2026-11-12T06:54:29Z)
59d8382d9c62 ready for maintainer review 0 active finding(s), 4 resolved finding(s) (at 2026-11-12T07:32:35Z)
cf2af96744e1 ready for maintainer review 0 active finding(s), 4 resolved finding(s) (at 2026-11-12T09:03:58Z)

tinysweeper 0.1.2

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

tinysweeper found nothing blocking. Approving.

Diagnostics

Total spend: $0.0211

@tinysweeper tinysweeper Bot added the priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. label Nov 11, 2026

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Requesting changes: 1 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

Diagnostics

Total spend: $0.0065

Comment thread crates/tinybox-linux/src/sandbox/mod.rs Resolved
@tinysweeper tinysweeper Bot added priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition. and removed priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. labels Nov 11, 2026

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Requesting changes: 1 lane(s) blocking, worst finding is low.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

Diagnostics

Total spend: $0.0083

…onment

Namespace exec dropped the caller's stdin (it always had), and with the
environment now on bwrap's stdin it could not carry both. A command with no
environment now gets the caller's stdin; one with both is refused before it
runs, rather than either being silently dropped.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The previously-blocking findings are resolved. Clearing the changes request.

Diagnostics

Total spend: $0.0048

@tinysweeper tinysweeper Bot added priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. and removed priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition. labels Nov 12, 2026
@M3gA-Mind
M3gA-Mind merged commit 1475773 into tinyhumansai:main Nov 12, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant