(
program: &str,
args: &[String],
workdir: Option<&str>,
timeout_secs: u64,
interactive: bool,
sandbox_id: Option<&str>,
openshell_endpoint: Option<&str>,
ssh_socket_pa
| 48 | /// fails to spawn, or if waiting for the child returns an OS error. |
| 49 | #[allow(clippy::too_many_arguments, clippy::implicit_hasher)] |
| 50 | pub async fn run_process( |
| 51 | program: &str, |
| 52 | args: &[String], |
| 53 | workdir: Option<&str>, |
| 54 | timeout_secs: u64, |
| 55 | interactive: bool, |
| 56 | sandbox_id: Option<&str>, |
| 57 | openshell_endpoint: Option<&str>, |
| 58 | ssh_socket_path: Option<String>, |
| 59 | policy: &SandboxPolicy, |
| 60 | entrypoint_pid: Arc<AtomicU32>, |
| 61 | provider_credentials: ProviderCredentialState, |
| 62 | provider_env: std::collections::HashMap<String, String>, |
| 63 | ca_file_paths: Option<(std::path::PathBuf, std::path::PathBuf)>, |
| 64 | #[cfg(target_os = "linux")] netns: Option<&NetworkNamespace>, |
| 65 | #[cfg(target_os = "linux")] bypass_denial_tx: Option< |
| 66 | tokio::sync::mpsc::UnboundedSender<DenialEvent>, |
| 67 | >, |
| 68 | #[cfg(target_os = "linux")] bypass_activity_tx: Option<ActivitySender>, |
| 69 | ) -> Result<i32> { |
| 70 | // When a driver injects a custom UID/GID, update /etc/passwd and |
| 71 | // /etc/group so the "sandbox" entry matches. Must run before |
| 72 | // validate_sandbox_user so passwd lookups see the correct identity. |
| 73 | #[cfg(unix)] |
| 74 | crate::process::update_sandbox_passwd_entries()?; |
| 75 | |
| 76 | // Validate that the sandbox user exists in the image. All sandbox images |
| 77 | // must include a "sandbox" user for privilege dropping; failing fast here |
| 78 | // beats silently running children as root. |
| 79 | #[cfg(unix)] |
| 80 | crate::process::validate_sandbox_user(policy)?; |
| 81 | #[cfg(unix)] |
| 82 | crate::process::validate_sandbox_group(policy)?; |
| 83 | |
| 84 | // Create read_write directories and chown newly-created ones to the |
| 85 | // sandbox user/group. Runs as the supervisor (root) before the child |
| 86 | // is forked so the workload sees writable paths it owns. |
| 87 | #[cfg(unix)] |
| 88 | crate::process::prepare_filesystem(policy)?; |
| 89 | |
| 90 | // Eagerly fetch initial settings and install the agent skill if the |
| 91 | // proposals flag is on at startup, rather than waiting for the policy |
| 92 | // poll loop's first tick. In offline/file-mode there is no gateway, so |
| 93 | // the flag stays at its default (false) and no skill is installed. |
| 94 | install_initial_agent_skill(sandbox_id, openshell_endpoint).await; |
| 95 | |
| 96 | // Install the supervisor seccomp prelude before spawning any workload-side |
| 97 | // tasks. By this point the orchestrator has finished privileged startup |
| 98 | // helpers (network namespace setup, nftables probes via run_networking), |
| 99 | // and the SSH listener and entrypoint child have not been exposed yet. |
| 100 | crate::sandbox::apply_supervisor_startup_hardening()?; |
| 101 | |
| 102 | // Spawn the bypass detection monitor. It tails dmesg for nftables LOG |
| 103 | // entries fired by rules installed on the workload's network namespace |
| 104 | // and reports direct connection attempts that would have bypassed the |
| 105 | // proxy. Spawn it before the entrypoint child so the first packets are |
| 106 | // not missed. Best-effort: returns None when dmesg is unavailable. |
| 107 | #[cfg(target_os = "linux")] |
no test coverage detected