Skip to content

core: add a sandbox-backed fs helper#14989

Open
bolinfest wants to merge 1 commit intomainfrom
pr14989
Open

core: add a sandbox-backed fs helper#14989
bolinfest wants to merge 1 commit intomainfrom
pr14989

Conversation

@bolinfest
Copy link
Copy Markdown
Collaborator

@bolinfest bolinfest commented Mar 17, 2026

Why

Local filesystem reads were still happening in-process, which meant they could bypass the sandbox boundary that exec actually enforces. If filesystem access is supposed to be governed by the same sandbox machinery as command execution, the read itself needs to happen in a sandboxed child process rather than through host-side std::fs calls.

This PR is intentionally the infra-only base of the stack. It adds the helper and execution plumbing needed for sandbox-backed file reads; the view_image migration lives in #15213, and stdin-backed write plumbing lives in #15187.

What changed

  • added a new internal codex-fs-ops crate, plus the Cargo/Bazel wiring for it, to host a small helper that currently supports read PATH and streams the file to stdout
  • taught codex-arg0 to re-exec the current binary in that helper mode via --codex-run-as-fs-ops
  • made the helper reject non-regular files and serialize runtime failures to stderr, so callers get a concrete error instead of hanging on special files such as /dev/zero or losing the underlying I/O failure
  • added core/src/sandboxed_fs.rs, which builds a sandboxed CommandSpec for that helper and exposes read_file() for follow-up callers
  • extended the exec path in core/src/exec.rs and core/src/sandboxing/mod.rs with a raw-output entry point so trusted internal helpers can capture stdout as bytes instead of lossy text while still reusing the existing FullBuffer capture policy

Testing

  • cargo test -p codex-fs-ops

Stack created with Sapling. Best reviewed with ReviewStack.

@bolinfest bolinfest changed the title feat: introduce sandbox-aware filesystem abstraction core: route view_image through a sandbox-backed fs helper Mar 17, 2026
@bolinfest bolinfest force-pushed the pr14989 branch 10 times, most recently from 753a0bd to 2d5a531 Compare March 18, 2026 21:52
@bolinfest bolinfest changed the title core: route view_image through a sandbox-backed fs helper core: add a sandbox-backed filesystem helper Mar 18, 2026
@bolinfest bolinfest force-pushed the pr14989 branch 5 times, most recently from bfe54b7 to 40ba316 Compare March 19, 2026 16:28
@bolinfest bolinfest changed the title core: add a sandbox-backed filesystem helper core: route view_image through a sandbox-backed fs helper Mar 19, 2026
@bolinfest bolinfest force-pushed the pr14989 branch 3 times, most recently from 5d9ef97 to 29d2549 Compare March 19, 2026 19:36
@bolinfest bolinfest changed the title core: route view_image through a sandbox-backed fs helper core: add a sandbox-backed fs helper Mar 19, 2026
@bolinfest bolinfest force-pushed the pr14989 branch 4 times, most recently from 1ed9cf6 to ad6148a Compare March 19, 2026 22:42
@bolinfest bolinfest force-pushed the pr14989 branch 5 times, most recently from 7bda055 to 9e9ec89 Compare March 19, 2026 23:07
@bolinfest bolinfest force-pushed the pr14989 branch 5 times, most recently from 45b4632 to 98ea221 Compare March 20, 2026 03:34
@bolinfest bolinfest marked this pull request as ready for review March 20, 2026 03:36
@bolinfest bolinfest requested a review from pakrym-oai March 20, 2026 03:38
Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 98ea221446

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +73 to +77
SandboxedFsOperation::Read { ref path } => vec![
CODEX_CORE_FS_OPS_ARG1.to_string(),
READ_FILE_OPERATION_ARG.to_string(),
path.to_string_lossy().to_string(),
],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Stop lossy-encoding paths before invoking fs-ops

On Unix, AbsolutePathBuf/PathBuf can represent filenames that are not valid UTF-8, but this code converts the path with to_string_lossy() before passing it through argv. In that case the helper receives a different pathname (with replacement characters) and fails to open an existing file. fs-ops::parse_command_from_args already accepts OsString, so this re-exec path should preserve raw path bytes instead of round-tripping through String.

Useful? React with 👍 / 👎.

})
.map_err(std::io::Error::other)?;

execute(command, stdin, stdout)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Serialize fs helper read errors before exiting

Parse failures are written to stderr, but runtime I/O failures from File::open/copy are returned directly here and then dropped by arg0_dispatch when it turns Err(_) into exit code 1. That means common cases like ENOENT/EACCES reach sandboxed_fs::parse_helper_failure with empty stdout/stderr and get reported as no error details emitted, which makes the helper much harder to diagnose once callers start using it.

Useful? React with 👍 / 👎.

Comment on lines +86 to +87
expiration: ExecExpiration::Timeout(SANDBOXED_FS_TIMEOUT),
capture_policy: ExecCapturePolicy::FullBuffer,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Badge Reject unbounded special-file reads in FullBuffer mode

This helper is configured with ExecCapturePolicy::FullBuffer, and core/src/exec.rs disables both the retained-bytes cap and ExecExpiration for that mode. Because fs-ops/src/runner.rs then copies the opened path to stdout until EOF, calling read_file on a FIFO, /dev/zero, or a procfs pseudo-file will never finish and can grow memory without bound. Since read_file accepts arbitrary paths, it needs a regular-file check and/or its own size/timeout guard before any consumer starts routing user paths through it.

Useful? React with 👍 / 👎.

@bolinfest bolinfest force-pushed the pr14989 branch 6 times, most recently from b6af173 to 29633f0 Compare March 20, 2026 06:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant