{"record":{"id":"fb108d5810849d23","repo":"uutils/coreutils","slug":"safe-traversal-error-invalid-fd","errorCode":null,"errorMessage":"safe-traversal-error-invalid-fd","messagePattern":"safe-traversal-error-invalid-fd","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"src/uucore/src/lib/features/safe_traversal.rs","lineNumber":481,"sourceCode":"        // target truncated. Callers reach here right after unlinking `name`,\n        // which is precisely the window an attacker races.\n        let flags = OFlag::O_CREAT\n            | OFlag::O_WRONLY\n            | OFlag::O_TRUNC\n            | OFlag::O_CLOEXEC\n            | OFlag::O_NOFOLLOW;\n        let mode = Mode::from_bits_truncate(0o666); // Default file permissions\n\n        let fd: OwnedFd = openat(self.fd.as_fd(), name_cstr.as_c_str(), flags, mode)\n            .map_err(|e| io::Error::from_raw_os_error(e as i32))?;\n\n        Ok(fs::File::from(fd))\n    }\n\n    /// Create a DirFd from an existing file descriptor (takes ownership)\n    pub fn from_raw_fd(fd: RawFd) -> io::Result<Self> {\n        if fd < 0 {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                translate!(\"safe-traversal-error-invalid-fd\"),\n            ));\n        }\n        // SAFETY: We've verified fd >= 0, and the caller is transferring ownership\n        let owned_fd = unsafe { OwnedFd::from_raw_fd(fd) };\n        Ok(Self { fd: owned_fd })\n    }\n}\n\n/// Find the deepest existing directory ancestor for a path.\n///\n/// Returns the existing ancestor path and a list of components that need to be created.\n/// Uses `metadata` (follows symlinks) so that symlinks to directories are treated as\n/// existing ancestors rather than components to create.\nfn find_existing_ancestor(path: &Path) -> io::Result<(PathBuf, Vec<OsString>)> {\n    let mut current = path.to_path_buf();\n    let mut components: Vec<OsString> = Vec::new();","sourceCodeStart":463,"sourceCodeEnd":499,"githubUrl":"https://github.com/uutils/coreutils/blob/85295bbf788bfd7a6926ba692031563504b304b7/src/uucore/src/lib/features/safe_traversal.rs#L463-L499","documentation":"`DirFd::from_raw_fd` validates that the caller-supplied raw file descriptor is non-negative before taking ownership. A negative fd is invalid (and would make `OwnedFd::from_raw_fd` UB), so it returns `InvalidInput` with the localized \"safe-traversal-error-invalid-fd\" message.","triggerScenarios":"Calling `DirFd::from_raw_fd(-1)` — typically after an `open`/`openat` call returned -1 on error and the raw fd was forwarded without checking.","commonSituations":"FFI wrappers that forget to check the -1 error return of libc open/openat, scripts binding native traversal APIs, refactored code losing an error check.","solutions":["Check the raw fd >= 0 (i.e. the underlying open succeeded) before calling from_raw_fd","Return/propagate the original open error (errno) instead of the fd","Prefer APIs returning Result<OwnedFd> so the invalid case can't reach from_raw_fd"],"exampleFix":"// before\nlet fd = unsafe { libc::open(path.as_ptr(), flags) };\nDirFd::from_raw_fd(fd)?;\n// after\nlet fd = unsafe { libc::open(path.as_ptr(), flags) };\nif fd < 0 { return Err(io::Error::last_os_error()); }\nDirFd::from_raw_fd(fd)?;","handlingStrategy":"validation","validationCode":"fn safe_from_raw_fd(fd: std::os::fd::RawFd) -> io::Result<DirFd> {\n    if fd < 0 { return Err(io::Error::last_os_error()); }\n    DirFd::from_raw_fd(fd)\n}","typeGuard":"fn is_valid_fd(fd: i32) -> bool { fd >= 0 }","tryCatchPattern":"match DirFd::from_raw_fd(fd) {\n    Err(e) if e.kind() == io::ErrorKind::InvalidInput => {\n        return Err(io::Error::last_os_error());\n    }\n    other => other?,\n}","preventionTips":["Always check libc open/openat return values before wrapping","Prefer Result-returning wrappers over raw fd plumbing","Run code under a debug allocator that flags invalid fds"],"tags":["fd","unsafe","traversal"],"backgroundTag":"invalid-file-descriptor","analyzedSha":"85295bbf788bfd7a6926ba692031563504b304b7","analyzedAt":"2026-08-31T11:11:36.175Z","contentChangedAt":"2026-08-31T11:11:36.175Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}