Skip to content

macOS 14.2: sandbox startup fails with unbound variable TIOCSTI #45119

Description

@bibryam

Environment

  • macOS 14.2 (23C64), Apple Silicon.
  • Codex desktop 26.908.40834, bundle build 8881.
  • Bundled CLI: codex-cli 0.154.0-alpha.6.2.
  • Also inspected current upstream main at 70eb36203dbb8c75d006b39cdfae74bd04e18a65; it contains the same symbolic rule.
  • No model request, account access, or project is needed to reproduce.

Reproduction

Run the desktop app's bundled executable from a terminal:

/Applications/Codex.app/Contents/Resources/codex sandbox -P :read-only -- /usr/bin/true

Actual result: exit 65, before /usr/bin/true starts:

sandbox-exec: unbound variable: TIOCSTI at <input string>, line 132, column 33

Backtrace:
<input string>:132:33:
    TIOCSTI

Expected result: /usr/bin/true starts inside the sandbox and exits 0.

Both this installed build and current upstream use the following sandbox syntax (macos is not a subcommand in either):

codex sandbox -P :read-only -- /usr/bin/true

In the desktop app, browser-controller startup fails with the same error before its Node kernel starts. This prevents browser tasks from running; resetting the browser controller reproduces it.

Root cause

The guard added by #42590 in codex-rs/cli/src/debug_sandbox.rs appends:

(deny file-ioctl (ioctl-command TIOCSTI))

On this macOS version, the Seatbelt policy compiler does not define the bare TIOCSTI symbol. The ioctl itself exists: the platform constant is 0x80017472 (2147578994). A minimal policy using the symbolic name reproduces the compilation error; replacing it with the numeric value compiles.

The proposed correction formats the existing platform libc::TIOCSTI constant into that rule. It preserves the denial, rule order, and sandbox permissions; it does not disable terminal-injection protection.

Validation and reference patch

Tested the reference correction on this same macOS 14.2 host, using Rust 1.95.0:

  • just fmt and git diff --check: passed.
  • just test -p codex-cli --test sandbox_tty: 2 passed, 0 skipped.
  • just test -p codex-cli --success-output immediate: 451 passed, 0 skipped.
  • target/debug/codex sandbox -P :read-only -- /usr/bin/true: exit 0.

The two Seatbelt tests execute the startup regression and a disposable-PTY control/denial probe. The latter confirms that TIOCSTI succeeds on the unsandboxed control PTY but is denied with EPERM inside the sandbox, with no injected input left queued. Tests ran outside a parent Seatbelt sandbox; the availability check did not skip them.

Reference patch and regression tests: bibryam#1

This issue follows the repository's contribution policy: the code is provided in the reporter's fork as a reference, not as an external upstream PR. No installed app binaries or security settings were modified.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLIbugSomething isn't workingsandboxIssues related to permissions or sandboxing

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions