{"record":{"id":"f1d61e9e94b7a2bf","repo":"astrid-runtime/astrid","slug":"opened-representation-entry-is-redirected-or-not-a","errorCode":null,"errorMessage":"opened representation entry is redirected or not a regular file","messagePattern":"opened representation entry is redirected or not a regular file","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/astrid-storage/src/engine/durable/representations/contiguous/namespace.rs","lineNumber":121,"sourceCode":"    #[cfg(unix)]\n    {\n        use cap_std::fs::OpenOptionsExt as _;\n        options.custom_flags(libc::O_NOFOLLOW | libc::O_NONBLOCK);\n    }\n    #[cfg(windows)]\n    {\n        use cap_std::fs::OpenOptionsExt as _;\n        use windows_sys::Win32::Storage::FileSystem::FILE_FLAG_OPEN_REPARSE_POINT;\n        options.custom_flags(FILE_FLAG_OPEN_REPARSE_POINT);\n    }\n}\n\npub(in crate::engine::durable::representations) fn validate_opened_regular(\n    file: &File,\n) -> io::Result<()> {\n    let metadata = file.metadata()?;\n    if !metadata.is_file() || opened_file_is_redirected(&metadata) {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            \"opened representation entry is redirected or not a regular file\",\n        ));\n    }\n    Ok(())\n}\n\n#[cfg(windows)]\nfn opened_file_is_redirected(metadata: &std::fs::Metadata) -> bool {\n    use std::os::windows::fs::MetadataExt as _;\n    use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_REPARSE_POINT;\n\n    metadata.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT != 0\n}\n\n#[cfg(not(windows))]\nconst fn opened_file_is_redirected(_metadata: &std::fs::Metadata) -> bool {\n    false","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage/src/engine/durable/representations/contiguous/namespace.rs#L103-L139","documentation":"validate_opened_regular stats an already-opened representation File and rejects it if it is not a regular file or if opened_file_is_redirected reports redirection (e.g. opened via /proc-style magic link). This InvalidData error ensures the handle the library holds truly refers to a regular file at open time.","triggerScenarios":"Calling open_file on an entry that was swapped to a non-regular object between path validation and open, or opened through a redirection (e.g. O_PATH/magic-link tricks) so metadata on the handle reports a non-file.","commonSituations":"TOCTOU races with concurrent deletion/recreation of representation files; exploits using magic symlinks to redirect opens; corrupted namespace entries pointing at devices or FIFOs.","solutions":["Reopen the file after the racing writer has finished; the validation passes on a stable file","Eliminate concurrent processes that replace representation files during reads/writes","Use the library's locking or a single-owner process model for the store","Audit for symlink/magic-link exposure of the store path and block it at the filesystem level"],"exampleFix":"// before\nfs::write(\"store/rep/f\", data) // another job replaces f with a fifo mid-open\n// after\nexclusive_lock(store); write; unlock","handlingStrategy":"retry","validationCode":"// verify path target before opening\nlet md = path.symlink_metadata()?;\nif !md.is_file() { return Err(\"representation entry is not a regular file\"); }","typeGuard":null,"tryCatchPattern":"match open_file_result {\n    Err(e) if e.kind() == io::ErrorKind::InvalidData => {\n        // likely a swap race; wait for writer completion and reopen\n        std::thread::sleep(Duration::from_millis(50));\n        open_file(path)\n    }\n    r => r,\n}","preventionTips":["Avoid concurrent replacement of representation files while readers are open","Use the store single-owner / lock discipline","Keep the store off paths other users can modify","Treat repeated failures as a tampering or corruption signal"],"tags":["io","filesystem","race-condition","security"],"backgroundTag":"file-changed-during-open","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}