{"record":{"id":"4176e003936e7f9b","repo":"openai/codex","slug":"failed-to-exec-bundled-bubblewrap-via-fd-path","errorCode":null,"errorMessage":"failed to exec bundled bubblewrap {} via {fd_path}: {err}","messagePattern":"failed to exec bundled bubblewrap (.+?) via (.+?): (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"codex-rs/linux-sandbox/src/bundled_bwrap.rs","lineNumber":67,"sourceCode":"\n        let fd_path = format!(\"/proc/self/fd/{}\", bwrap_file.as_raw_fd());\n        let program_cstring = CString::new(fd_path.as_str())\n            .unwrap_or_else(|err| panic!(\"invalid bundled bubblewrap fd path: {err}\"));\n        let cstrings = argv_to_cstrings(&argv);\n        let mut argv_ptrs: Vec<*const c_char> = cstrings\n            .iter()\n            .map(CString::as_c_str)\n            .map(CStr::as_ptr)\n            .collect();\n        argv_ptrs.push(std::ptr::null());\n\n        // SAFETY: `program_cstring` and every entry in `argv_ptrs` are valid C\n        // strings for the duration of the call. On success `execv` does not return.\n        unsafe {\n            libc::execv(program_cstring.as_ptr(), argv_ptrs.as_ptr());\n        }\n        let err = std::io::Error::last_os_error();\n        panic!(\n            \"failed to exec bundled bubblewrap {} via {fd_path}: {err}\",\n            self.program.as_path().display()\n        );\n    }\n}\n\nfn find_for_install_context(context: &InstallContext) -> Option<AbsolutePathBuf> {\n    context\n        .bundled_resource(\"bwrap\")\n        .filter(|path| is_executable_file(path))\n}\n\nfn find_legacy_for_exe(exe: &Path) -> Option<AbsolutePathBuf> {\n    legacy_candidates_for_exe(exe)\n        .into_iter()\n        .find(|candidate| is_executable_file(candidate))\n        .map(|path| {\n            AbsolutePathBuf::from_absolute_path(&path).unwrap_or_else(|err| {","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/linux-sandbox/src/bundled_bwrap.rs#L49-L85","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Read the errno in the panic text: for EACCES, remount the relevant filesystem without noexec or relocate codex-resources to an exec-permitted path.","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.","Check audit logs for SELinux/AppArmor denials on the fd path and adjust the policy or file labels.","Fall back to a system-installed bubblewrap when the environment forbids executing bundled binaries."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Before launching: ensure the mount backing the resource permits exec\nfn mount_allows_exec(path: &std::path::Path) -> bool {\n    let mounts = std::fs::read_to_string(\"/proc/mounts\").unwrap_or_default();\n    !mounts.lines().any(|line| {\n        let mut parts = line.split_whitespace();\n        let _dev = parts.next();\n        let Some(dir) = parts.next() else { return false; };\n        path.starts_with(dir) && line.contains(\"noexec\")\n    })\n}\nif !mount_allows_exec(&bwrap_path) {\n    // relocate resources or use system bwrap instead of launching\n}","typeGuard":null,"tryCatchPattern":"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.","preventionTips":["Mount /proc and the install directory without noexec on hosts that run the sandbox.","Prefer static (musl) builds for hardened or minimal images.","Smoke-test the sandbox once per host or image so exec-policy problems surface at deploy time, not mid-task."],"tags":["rust","linux","sandbox","bubblewrap","exec","permissions","panic"],"backgroundTag":"exec-permission-denied","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}