{"record":{"id":"893288fbc7901038","repo":"astrid-runtime/astrid","slug":"winfsp-service-control-request-exceeds-limit","errorCode":null,"errorMessage":"WinFsp service control request exceeds limit","messagePattern":"WinFsp service control request exceeds limit","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-provider-winfsp/src/win.rs","lineNumber":434,"sourceCode":"                    return Ok(());\n                }\n            },\n        }\n    }\n}\n\nasync fn read_service_control(\n    stream: &mut local_transport::LocalStream,\n) -> Result<ServiceControlRequest> {\n    let mut line = String::new();\n    let reader = tokio::io::BufReader::new(stream);\n    let read = reader\n        .take((SERVICE_MAX_CONTROL_BYTES + 1) as u64)\n        .read_line(&mut line)\n        .await\n        .context(\"read WinFsp service control request\")?;\n    if read == 0 || line.len() > SERVICE_MAX_CONTROL_BYTES {\n        bail!(\"WinFsp service control request exceeds limit\");\n    }\n    serde_json::from_str(&line).context(\"decode WinFsp service control request\")\n}\n\nasync fn write_service_control(\n    stream: &mut local_transport::LocalStream,\n    response: &ServiceControlResponse,\n) -> Result<()> {\n    let bytes = serde_json::to_vec(response)?;\n    stream.write_all(&bytes).await?;\n    stream.write_all(b\"\\n\").await?;\n    stream.flush().await.context(\"flush WinFsp service control\")\n}\n\nfn parent_is_alive(\n    parent: &astrid_core::storage_filesystem::StorageProviderParentLifetimeV1,\n) -> bool {\n    // SAFETY: OpenProcess/GetExitCodeProcess/CloseHandle are called with a","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-provider-winfsp/src/win.rs#L416-L452","documentation":"read_service_control reads one newline-delimited JSON control request from the local stream, capped at SERVICE_MAX_CONTROL_BYTES (64 KiB). If the line is empty (EOF) or longer than 64 KiB, the request is rejected to bound memory use and prevent abuse of the control socket.","triggerScenarios":"A control client connects to the control socket and sends a line longer than 65535 bytes, or closes the connection before sending any data (read == 0).","commonSituations":"A custom tool writing oversized JSON control commands; a client that dumps a blob without newlines so the whole payload exceeds the cap; connecting and disconnecting without writing (health-check probes); binary data sent to the socket with no newline.","solutions":["Split large control payloads into smaller requests or use the file-based control channel instead of the socket line protocol.","Ensure the control client appends a newline and keeps each JSON request under 64 KiB.","Fix health-check/probe clients to send a minimal valid request or close cleanly without partial writes.","Check the client for binary/UTF-8-invalid output that prevents the line terminator from appearing."],"exampleFix":"// before\nlet giant = serde_json::to_string(&huge_request)?; // > 64 KiB\nstream.write_all(giant.as_bytes()).await?;\n// after\nlet compact = serde_json::to_string(&request.trim_to_control_limit())?;\nstream.write_all(format!(\"{compact}\\n\").as_bytes()).await?;","handlingStrategy":"validation","validationCode":"const SERVICE_MAX_CONTROL_BYTES: usize = 64 * 1024;\nfn control_request_is_within_limit(json: &str) -> bool {\n    !json.is_empty() && json.len() <= SERVICE_MAX_CONTROL_BYTES && json.ends_with('\\n')\n}","typeGuard":null,"tryCatchPattern":"match send_control(&stream, &request).await {\n    Err(e) if e.to_string().contains(\"exceeds limit\") => {\n        // shrink or split the control request below 64 KiB and retry\n        Err(e)\n    },\n    other => other,\n}","preventionTips":["Keep control JSON small and always newline-terminated.","Never pipe binary data into the control socket.","Exclude control sockets from naive TCP health checks that open/close without writing."],"tags":["limit-exceeded","protocol","ipc"],"backgroundTag":"payload-too-large","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"}