openai/codex · critical

failed to exec bundled bubblewrap {} via {fd_path}: {err}

Error message

failed to exec bundled bubblewrap {} via {fd_path}: {err}

What it means

exec() calls libc::execv on the /proc/self/fd/N path of the digest-verified bwrap. execv returns only on failure, and the code panics with the OS error from std::io::Error::last_os_error(). The errno identifies the cause: EACCES when the file or the filesystem holding it is mounted noexec or exec permission was lost; ENOENT when the ELF interpreter/loader named in the binary is missing; also ENOMEM, ELOOP, or ETXTBSY.

Source

Thrown at codex-rs/linux-sandbox/src/bundled_bwrap.rs:67

        let fd_path = format!("/proc/self/fd/{}", bwrap_file.as_raw_fd());
        let program_cstring = CString::new(fd_path.as_str())
            .unwrap_or_else(|err| panic!("invalid bundled bubblewrap fd path: {err}"));
        let cstrings = argv_to_cstrings(&argv);
        let mut argv_ptrs: Vec<*const c_char> = cstrings
            .iter()
            .map(CString::as_c_str)
            .map(CStr::as_ptr)
            .collect();
        argv_ptrs.push(std::ptr::null());

        // SAFETY: `program_cstring` and every entry in `argv_ptrs` are valid C
        // strings for the duration of the call. On success `execv` does not return.
        unsafe {
            libc::execv(program_cstring.as_ptr(), argv_ptrs.as_ptr());
        }
        let err = std::io::Error::last_os_error();
        panic!(
            "failed to exec bundled bubblewrap {} via {fd_path}: {err}",
            self.program.as_path().display()
        );
    }
}

fn find_for_install_context(context: &InstallContext) -> Option<AbsolutePathBuf> {
    context
        .bundled_resource("bwrap")
        .filter(|path| is_executable_file(path))
}

fn find_legacy_for_exe(exe: &Path) -> Option<AbsolutePathBuf> {
    legacy_candidates_for_exe(exe)
        .into_iter()
        .find(|candidate| is_executable_file(candidate))
        .map(|path| {
            AbsolutePathBuf::from_absolute_path(&path).unwrap_or_else(|err| {

View on GitHub (pinned to 339751715c)

Solutions

  1. Read the errno in the panic text: for EACCES, remount the relevant filesystem without noexec or relocate codex-resources to an exec-permitted path.
  2. For ENOENT, run readelf -l on the bwrap binary and provide the interpreter it names, or switch to a static/musl build of the package.
  3. Check audit logs for SELinux/AppArmor denials on the fd path and adjust the policy or file labels.
  4. Fall back to a system-installed bubblewrap when the environment forbids executing bundled binaries.
Defensive patterns

Strategy: fallback

Validate before calling

// Before launching: ensure the mount backing the resource permits exec
fn mount_allows_exec(path: &std::path::Path) -> bool {
    let mounts = std::fs::read_to_string("/proc/mounts").unwrap_or_default();
    !mounts.lines().any(|line| {
        let mut parts = line.split_whitespace();
        let _dev = parts.next();
        let Some(dir) = parts.next() else { return false; };
        path.starts_with(dir) && line.contains("noexec")
    })
}
if !mount_allows_exec(&bwrap_path) {
    // relocate resources or use system bwrap instead of launching
}

Try / catch

execv replaces the process on success, so catch_unwind only observes the failure case: wrap the launch in std::panic::catch_unwind and, when the payload mentions 'failed to exec bundled bubblewrap', fall back to a system bwrap launcher for the same argv.

Prevention

When it happens

Trigger: Launching a sandboxed command when /proc (or the mount backing the bundled bwrap) is mounted noexec; a distroless/minimal container lacking the dynamic loader the bwrap build expects; SELinux/AppArmor denying execution of procfd paths; the binary being rewritten concurrently (ETXTBSY).

Common situations: Hardened Docker/Kubernetes hosts with noexec on /proc, /tmp, or volume mounts; minimal images without ld-musl or ld-linux; SELinux policies blocking exec of memfd/procfd files; overlay/FUSE mounts with unusual exec semantics.

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/4176e003936e7f9b. Report an issue: GitHub.