{"record":{"id":"e14b9577bfa11d43","repo":"astrid-runtime/astrid","slug":"mount-data-has-nul","errorCode":null,"errorMessage":"mount data has NUL","messagePattern":"mount data has NUL","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-vfs/src/workspace_cow/overlayfs.rs","lineNumber":500,"sourceCode":"fn path_hash(path: &Path) -> String {\n    use std::collections::hash_map::DefaultHasher;\n    use std::hash::{Hash, Hasher};\n    let key = std::fs::canonicalize(path).unwrap_or_else(|_| path.to_path_buf());\n    let mut hasher = DefaultHasher::new();\n    key.hash(&mut hasher);\n    format!(\"{:016x}\", hasher.finish())\n}\n\n/// `mount(\"overlay\", target, \"overlay\", 0, data)`.\nfn mount_overlay(target: &Path, data: &str) -> io::Result<()> {\n    let src = CString::new(\"overlay\")\n        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, \"mount source has NUL\"))?;\n    let fstype = CString::new(\"overlay\")\n        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, \"mount fstype has NUL\"))?;\n    let target_c = CString::new(target.as_os_str().as_bytes())\n        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, \"mount target has NUL\"))?;\n    let data_c = CString::new(data)\n        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, \"mount data has NUL\"))?;\n    // SAFETY: all four pointers are valid, NUL-terminated C strings that outlive\n    // the call; `mount` reads them and returns a status code, retaining no\n    // pointers. `data` is the overlayfs option string.\n    let rc = unsafe {\n        libc::mount(\n            src.as_ptr(),\n            target_c.as_ptr(),\n            fstype.as_ptr(),\n            0,\n            data_c.as_ptr().cast(),\n        )\n    };\n    if rc != 0 {\n        return Err(io::Error::last_os_error());\n    }\n    Ok(())\n}\n","sourceCodeStart":482,"sourceCodeEnd":518,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-vfs/src/workspace_cow/overlayfs.rs#L482-L518","documentation":"mount_overlay converts the overlayfs data option string (lowerdir=/upperdir=/workdir=...) to a CString for mount(2). If the assembled data string contains an embedded NUL byte, CString::new fails and the function returns InvalidInput 'mount data has NUL'.","triggerScenarios":"Calling mount (→ mount_overlay) when the data string built from layer directory paths contains an interior '\\0' — i.e. one of the layer paths fed into the option string contains NUL.","commonSituations":"Layer/workspace paths derived from binary data or untrimmed buffers; corrupted configuration supplying layer directories with embedded NULs.","solutions":["Validate each layer path (lowerdir/upperdir/workdir) for NUL bytes before assembling the data string","Since validate inputs are Paths, check as_os_str().as_bytes().contains(&0) upstream","Reject NUL-containing paths at the workspace configuration boundary","Log the data string (NUL-escaped) to find which layer path is bad"],"exampleFix":"// before\nlet data = format!(\"lowerdir={},upperdir={},workdir={}\", lower, upper, work);\nmount_overlay(target, &data)?;\n// after\nfor p in [&lower, &upper, &work] {\n    if p.as_os_str().as_bytes().contains(&0) { return Err(...); }\n}\nmount_overlay(target, &data)?;","handlingStrategy":"validation","validationCode":"for p in [&lower, &upper, &work] { if p.as_os_str().as_bytes().contains(&0) { return Err(io::Error::new(io::ErrorKind::InvalidInput, \"layer path contains NUL\")); } }","typeGuard":"fn layer_ok(p: &Path) -> bool { !p.as_os_str().as_bytes().contains(&0) }","tryCatchPattern":"match mount(target, &layers) { Err(e) if e.kind() == io::ErrorKind::InvalidInput => { /* inspect layer paths for NUL, fail the workspace setup */ }, other => other, }","preventionTips":["Validate every layer directory path before assembling the overlayfs data string","Keep layer paths sourced from typed config, not raw bytes","Log the data string NUL-escaped when mount fails for diagnosis"],"tags":["ffi","mount","overlayfs","invalid-input"],"backgroundTag":"invalid-argument-value","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}