{"record":{"id":"fa2effa128f776f8","repo":"astrid-runtime/astrid","slug":"winfsp-service-control-path-is-malformed","errorCode":null,"errorMessage":"WinFsp service control path is malformed","messagePattern":"WinFsp service control path is malformed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-provider-winfsp/src/win.rs","lineNumber":320,"sourceCode":"        || lease.resource_path.starts_with(&launch.mountpoint)\n    {\n        bail!(\"WinFsp service mountpoint is public or overlaps the lease resource\");\n    }\n    platform_fs::validate_private_directory(&launch.mountpoint)\n        .context(\"validate private WinFsp mountpoint\")?;\n    platform_fs::verify_no_redirects(&launch.mountpoint)\n        .context(\"reject redirected WinFsp mountpoint\")?;\n    if std::fs::read_dir(&launch.mountpoint)?.next().is_some() {\n        bail!(\"WinFsp service mountpoint is not empty\");\n    }\n    if !launch.control_path.is_absolute()\n        || launch\n            .control_path\n            .components()\n            .any(|component| matches!(component, std::path::Component::ParentDir))\n        || launch.control_path != lease.resource_path.join(\"process-control.sock\")\n    {\n        bail!(\"WinFsp service control path is malformed\");\n    }\n    let control_parent = launch\n        .control_path\n        .parent()\n        .context(\"WinFsp service control path has no parent\")?;\n    platform_fs::validate_private_directory(control_parent)\n        .context(\"validate private WinFsp control parent\")?;\n    platform_fs::verify_no_redirects(&launch.control_path)\n        .context(\"reject redirected WinFsp control path\")?;\n    if local_transport::endpoint_is_present(&launch.control_path)\n        .context(\"inspect WinFsp service control endpoint\")?\n    {\n        bail!(\"WinFsp service control endpoint is already present\");\n    }\n    Ok(())\n}\n\nasync fn probe_callback(launch: &StorageProviderServiceLaunchV1) -> Result<()> {","sourceCodeStart":302,"sourceCodeEnd":338,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-provider-winfsp/src/win.rs#L302-L338","documentation":"validate_service_launch rejects a WinFsp service launch whose control_path fails structural or canonical-form checks: it must not contain '..' components, and it must exactly equal the lease resource path joined with \"process-control.sock\". The library enforces this so the private control socket lands in a predictable, non-escapable location tied to the mount lease.","triggerScenarios":"Calling the WinFsp service entry (service_main -> validate_service_launch) with a StorageProviderServiceLaunchV1 whose control_path contains a ParentDir ('..') component, or whose control_path differs from lease.resource_path.join(\"process-control.sock\").","commonSituations":"Hand-constructed launch configs for testing; templating bugs that resolve or relativize paths with '..'; moving the control socket to a custom directory for shared mounts; tools that normalize paths (e.g. a/../b) before passing them in.","solutions":["Set control_path to exactly lease.resource_path.join(\"process-control.sock\") and let the library derive it rather than hardcoding it.","Remove any '..' components from control_path by canonicalizing the resource path before building the launch struct.","If you need a different socket location, change the lease resource_path, not the control_path."],"exampleFix":"// before\nlaunch.control_path = PathBuf::from(\"/var/run/mounts/../m-123/process-control.sock\");\n// after\nlaunch.control_path = lease.resource_path.join(\"process-control.sock\");","handlingStrategy":"validation","validationCode":"let expected = lease.resource_path.join(\"process-control.sock\");\nif launch.control_path != expected\n    || launch.control_path.components().any(|c| matches!(c, std::path::Component::ParentDir)) {\n    return Err(anyhow!(\"control_path must be {:?}\", expected));\n}","typeGuard":"fn control_path_is_canonical(launch: &StorageProviderServiceLaunchV1, lease: &Lease) -> bool {\n    launch.control_path == lease.resource_path.join(\"process-control.sock\")\n        && !launch.control_path.components().any(|c| matches!(c, std::path::Component::ParentDir))\n}","tryCatchPattern":"match validate_service_launch(&launch) {\n    Err(e) if e.to_string().contains(\"control path is malformed\") => {\n        // rebuild control_path from lease and retry once\n    },\n    other => other?,\n}","preventionTips":["Always derive control_path from lease.resource_path, never hardcode it.","Canonicalize resource_path with its components before building the launch.","Add a unit test asserting control_path == resource_path.join(\"process-control.sock\")."],"tags":["path-validation","security","winfsp"],"backgroundTag":"path-traversal-blocked","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"}