Skip to content

Commit e4e76b5

Browse files
committed
fix(sandbox): add WSL2 GPU device and library paths to Landlock baseline
On WSL2, NVIDIA GPUs are exposed through the DXG kernel driver (/dev/dxg) rather than the native nvidia* devices. CDI injects /dev/dxg as the sole GPU device node, plus GPU libraries under /usr/lib/wsl/. has_gpu_devices() previously only checked for /dev/nvidiactl, which does not exist on WSL2, so GPU enrichment never ran. This meant /dev/dxg was never permitted by Landlock and /proc write access (required by CUDA for thread naming) was never granted. Fix by: - Extending has_gpu_devices() to also detect /dev/dxg - Adding /dev/dxg to GPU_BASELINE_READ_WRITE (device nodes need O_RDWR) - Adding /usr/lib/wsl to GPU_BASELINE_READ_ONLY for CDI-injected GPU library bind-mounts that may not be covered by the /usr parent rule across filesystem boundaries The existing path existence check in enrich_proto_baseline_paths() ensures all new entries are silently skipped on native Linux where these paths do not exist.
1 parent c54a7cd commit e4e76b5

1 file changed

Lines changed: 61 additions & 5 deletions

File tree

  • crates/openshell-sandbox/src

crates/openshell-sandbox/src/lib.rs

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,14 +1234,31 @@ const PROXY_BASELINE_READ_WRITE: &[&str] = &["/sandbox", "/tmp"];
12341234
/// socket at init time. If the directory exists but Landlock denies traversal
12351235
/// (EACCES vs ECONNREFUSED), NVML returns `NVML_ERROR_INSUFFICIENT_PERMISSIONS`
12361236
/// even though the daemon is optional. Only read/traversal access is needed.
1237-
const GPU_BASELINE_READ_ONLY: &[&str] = &["/run/nvidia-persistenced"];
1237+
///
1238+
/// `/usr/lib/wsl`: On WSL2, CDI bind-mounts GPU libraries (libdxcore.so,
1239+
/// libcuda.so.1.1, etc.) into paths under `/usr/lib/wsl/`. Although `/usr`
1240+
/// is already in `PROXY_BASELINE_READ_ONLY`, individual file bind-mounts may
1241+
/// not be covered by the parent-directory Landlock rule when the mount crosses
1242+
/// a filesystem boundary. Listing `/usr/lib/wsl` explicitly ensures traversal
1243+
/// is permitted regardless of Landlock's cross-mount behaviour.
1244+
const GPU_BASELINE_READ_ONLY: &[&str] = &[
1245+
"/run/nvidia-persistenced",
1246+
"/usr/lib/wsl", // WSL2: CDI-injected GPU library directory
1247+
];
12381248

12391249
/// GPU read-write paths (static).
12401250
///
12411251
/// `/dev/nvidiactl`, `/dev/nvidia-uvm`, `/dev/nvidia-uvm-tools`,
1242-
/// `/dev/nvidia-modeset`: control and UVM devices injected by CDI.
1243-
/// Landlock restricts `open(2)` on device files even when DAC allows it;
1244-
/// these need read-write because NVML/CUDA opens them with `O_RDWR`.
1252+
/// `/dev/nvidia-modeset`: control and UVM devices injected by CDI on native
1253+
/// Linux. Landlock restricts `open(2)` on device files even when DAC allows
1254+
/// it; these need read-write because NVML/CUDA opens them with `O_RDWR`.
1255+
/// These devices do not exist on WSL2 and will be skipped by the existence
1256+
/// check in `enrich_proto_baseline_paths()`.
1257+
///
1258+
/// `/dev/dxg`: On WSL2, NVIDIA GPUs are exposed through the DXG kernel driver
1259+
/// (DirectX Graphics) rather than the native nvidia* devices. CDI injects
1260+
/// `/dev/dxg` as the sole GPU device node; it does not exist on native Linux
1261+
/// and will be skipped there by the existence check.
12451262
///
12461263
/// `/proc`: CUDA writes to `/proc/<pid>/task/<tid>/comm` during `cuInit()`
12471264
/// to set thread names. Without write access, `cuInit()` returns error 304.
@@ -1255,12 +1272,17 @@ const GPU_BASELINE_READ_WRITE: &[&str] = &[
12551272
"/dev/nvidia-uvm",
12561273
"/dev/nvidia-uvm-tools",
12571274
"/dev/nvidia-modeset",
1275+
"/dev/dxg", // WSL2: DXG device (GPU via DirectX kernel driver, injected by CDI)
12581276
"/proc",
12591277
];
12601278

12611279
/// Returns true if GPU devices are present in the container.
1280+
///
1281+
/// Checks both the native Linux NVIDIA control device (`/dev/nvidiactl`) and
1282+
/// the WSL2 DXG device (`/dev/dxg`). CDI injects exactly one of these
1283+
/// depending on the host kernel; the other will not exist.
12621284
fn has_gpu_devices() -> bool {
1263-
std::path::Path::new("/dev/nvidiactl").exists()
1285+
std::path::Path::new("/dev/nvidiactl").exists() || std::path::Path::new("/dev/dxg").exists()
12641286
}
12651287

12661288
/// Enumerate per-GPU device nodes (`/dev/nvidia0`, `/dev/nvidia1`, …).
@@ -1531,6 +1553,17 @@ mod baseline_tests {
15311553
);
15321554
}
15331555

1556+
#[test]
1557+
fn gpu_baseline_read_write_contains_dxg() {
1558+
// /dev/dxg must be present so WSL2 sandboxes get the Landlock
1559+
// read-write rule for the CDI-injected DXG device. The existence
1560+
// check in enrich_proto_baseline_paths() skips it on native Linux.
1561+
assert!(
1562+
GPU_BASELINE_READ_WRITE.contains(&"/dev/dxg"),
1563+
"/dev/dxg must be in GPU_BASELINE_READ_WRITE for WSL2 support"
1564+
);
1565+
}
1566+
15341567
#[test]
15351568
fn local_enrichment_preserves_explicit_read_only_for_baseline_read_write_paths() {
15361569
let mut policy = SandboxPolicy {
@@ -1565,6 +1598,29 @@ mod baseline_tests {
15651598
"baseline enrichment must not promote explicit read_only /tmp to read_write"
15661599
);
15671600
}
1601+
1602+
#[test]
1603+
fn gpu_baseline_read_only_contains_usr_lib_wsl() {
1604+
// /usr/lib/wsl must be present so CDI-injected WSL2 GPU library
1605+
// bind-mounts are accessible under Landlock. Skipped on native Linux.
1606+
assert!(
1607+
GPU_BASELINE_READ_ONLY.contains(&"/usr/lib/wsl"),
1608+
"/usr/lib/wsl must be in GPU_BASELINE_READ_ONLY for WSL2 CDI library paths"
1609+
);
1610+
}
1611+
1612+
#[test]
1613+
fn has_gpu_devices_reflects_dxg_or_nvidiactl() {
1614+
// Verify the OR logic: result must match the manual disjunction of
1615+
// the two path checks. Passes in all environments.
1616+
let nvidiactl = std::path::Path::new("/dev/nvidiactl").exists();
1617+
let dxg = std::path::Path::new("/dev/dxg").exists();
1618+
assert_eq!(
1619+
has_gpu_devices(),
1620+
nvidiactl || dxg,
1621+
"has_gpu_devices() should be true iff /dev/nvidiactl or /dev/dxg exists"
1622+
);
1623+
}
15681624
}
15691625

15701626
/// Load sandbox policy from local files or gRPC.

0 commit comments

Comments
 (0)