## Why `zsh-fork` sessions launched through unified-exec need the escalation socket to survive the wrapper -> server -> child handoff so later intercepted `exec()` calls can still reach the escalation server. The inherited-fd spawn path also needs to avoid closing Rust's internal exec-error pipe, and the shell-escalation handoff needs to tolerate the receive-side case where a transferred fd is installed into the same stdio slot it will be mapped onto. ## What Changed - Added `SpawnLifecycle::inherited_fds()` in `codex-rs/core/src/unified_exec/process.rs` and threaded inherited fds through `codex-rs/core/src/unified_exec/process_manager.rs` so unified-exec can preserve required descriptors across both PTY and no-stdin pipe spawn paths. - Updated `codex-rs/core/src/tools/runtimes/shell/zsh_fork_backend.rs` to expose the escalation socket fd through the spawn lifecycle. - Added inherited-fd-aware spawn helpers in `codex-rs/utils/pty/src/pty.rs` and `codex-rs/utils/pty/src/pipe.rs`, including Unix pre-exec fd pruning that preserves requested inherited fds while leaving `FD_CLOEXEC` descriptors alone. The pruning helper is now named `close_inherited_fds_except()` to better describe that behavior. - Updated `codex-rs/shell-escalation/src/unix/escalate_client.rs` to duplicate local stdio before transfer and send destination stdio numbers in `SuperExecMessage`, so the wrapper keeps using its own `stdin`/`stdout`/`stderr` until the escalated child takes over. - Updated `codex-rs/shell-escalation/src/unix/escalate_server.rs` so the server accepts the overlap case where a received fd reuses the same stdio descriptor number that the child setup will target with `dup2`. - Added comments around the PTY stdio wiring and the overlap regression helper to make the fd handoff and controlling-terminal setup easier to follow. ## Verification - `cargo test -p codex-utils-pty` - covers preserved-fd PTY spawn behavior, PTY resize, Python REPL continuity, exec-failure reporting, and the no-stdin pipe path - `cargo test -p codex-shell-escalation` - covers duplicated-fd transfer on the client side and verifies the overlap case by passing a pipe-backed stdin payload through the server-side `dup2` path --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/13644). * #14624 * __->__ #13644 |
||
|---|---|---|
| .. | ||
| src | ||
| BUILD.bazel | ||
| Cargo.toml | ||
| README.md | ||
codex-shell-escalation
This crate contains the Unix shell-escalation protocol implementation and the
codex-execve-wrapper executable.
codex-execve-wrapper receives the arguments to an intercepted execve(2) call and delegates the
decision to the shell-escalation protocol over a shared file descriptor (specified by the
CODEX_ESCALATE_SOCKET environment variable). The server on the other side replies with one of:
Run:codex-execve-wrappershould invokeexecve(2)on itself to run the original command within the sandboxed shell.Escalate: forward the file descriptors of the current process so the command can be run faithfully outside the sandbox. When the process completes, the server forwards the exit code back tocodex-execve-wrapper.Deny: the server has declared the proposed command to be forbidden, socodex-execve-wrapperprints an error tostderrand exits with1.
Patched Bash
We carry a small patch to execute_cmd.c (see patches/bash-exec-wrapper.patch) that adds support for EXEC_WRAPPER. The original commit message is “add support for BASH_EXEC_WRAPPER” and the patch applies cleanly to a8a1c2fac029404d3f42cd39f5a20f24b6e4fe4b from https://github.com/bminor/bash. To rebuild manually:
git clone https://git.savannah.gnu.org/git/bash
git checkout a8a1c2fac029404d3f42cd39f5a20f24b6e4fe4b
git apply /path/to/patches/bash-exec-wrapper.patch
./configure --without-bash-malloc
make -j"$(nproc)"