Skip to content

Commit 420c0df

Browse files
committed
feat: add --fs-mount CLI flag for mapping host paths into sandbox
Signed-off-by: Cong Wang <cwang@multikernel.io>
1 parent 2b3bae2 commit 420c0df

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

crates/sandlock-cli/src/main.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ enum Command {
100100
interactive: bool,
101101
#[arg(long = "fs-deny", value_name = "PATH")]
102102
fs_deny: Vec<String>,
103+
/// Mount a host path inside the sandbox (e.g. --fs-mount /work:/host/path)
104+
#[arg(long = "fs-mount", value_name = "VIRTUAL:HOST")]
105+
fs_mount: Vec<String>,
103106
/// CPU cores to pin the sandbox to (e.g. --cpu-cores 0,2,3)
104107
#[arg(long = "cpu-cores", value_delimiter = ',')]
105108
cpu_cores: Vec<u32>,
@@ -156,7 +159,7 @@ async fn main() -> Result<()> {
156159
fs_isolation, fs_storage, max_disk, net_allow, net_deny,
157160
http_allow, http_deny, http_ports, https_ca, https_key,
158161
port_remap, no_randomize_memory, no_huge_pages, deterministic_dirs, hostname, no_coredump,
159-
env_vars, exec_shell, interactive: _, fs_deny, cpu_cores, gpu_devices, image, dry_run, no_supervisor, cmd } =>
162+
env_vars, exec_shell, interactive: _, fs_deny, fs_mount, cpu_cores, gpu_devices, image, dry_run, no_supervisor, cmd } =>
160163
{
161164
if no_supervisor {
162165
validate_no_supervisor(
@@ -167,7 +170,7 @@ async fn main() -> Result<()> {
167170
no_huge_pages, deterministic_dirs, &hostname, &chroot,
168171
&image, &uid, &workdir, &cwd, &fs_isolation, &fs_storage,
169172
&max_disk, port_remap, &cpu_cores, &gpu_devices, dry_run,
170-
&status_fd, &fs_deny,
173+
&status_fd, &fs_deny, &fs_mount,
171174
)?;
172175

173176
// Build a minimal policy with only fs rules
@@ -267,6 +270,11 @@ async fn main() -> Result<()> {
267270
if let Some(cpu) = max_cpu { builder = builder.max_cpu(cpu); }
268271
if let Some(n) = max_open_files { builder = builder.max_open_files(n); }
269272
for p in &fs_deny { builder = builder.fs_deny(p); }
273+
for spec in &fs_mount {
274+
let (virt, host) = spec.split_once(':')
275+
.ok_or_else(|| anyhow!("--fs-mount requires VIRTUAL:HOST, got: {}", spec))?;
276+
builder = builder.fs_mount(virt, host);
277+
}
270278
if let Some(ref path) = chroot { builder = builder.chroot(path); }
271279
if let Some(id) = uid { builder = builder.uid(id); }
272280
if let Some(ref path) = workdir { builder = builder.workdir(path); }
@@ -496,6 +504,7 @@ fn validate_no_supervisor(
496504
dry_run: bool,
497505
status_fd: &Option<i32>,
498506
fs_deny: &[String],
507+
fs_mount: &[String],
499508
) -> Result<()> {
500509
let mut bad = Vec::new();
501510

@@ -533,6 +542,7 @@ fn validate_no_supervisor(
533542
if dry_run { bad.push("--dry-run"); }
534543
if status_fd.is_some() { bad.push("--status-fd"); }
535544
if !fs_deny.is_empty() { bad.push("--fs-deny"); }
545+
if !fs_mount.is_empty() { bad.push("--fs-mount"); }
536546

537547
if !bad.is_empty() {
538548
return Err(anyhow!(

0 commit comments

Comments
 (0)