@@ -34,6 +34,25 @@ fn scrub_sensitive_env(cmd: &mut Command) {
3434 cmd. env_remove ( SSH_HANDSHAKE_SECRET_ENV ) ;
3535}
3636
37+ #[ cfg( not( any(
38+ target_os = "macos" ,
39+ target_os = "ios" ,
40+ target_os = "haiku" ,
41+ target_os = "redox"
42+ ) ) ) ]
43+ fn has_gpu_devices ( ) -> bool {
44+ const GPU_DEVICE_PATHS : & [ & str ] = & [
45+ "/dev/nvidiactl" ,
46+ "/dev/nvidia-uvm" ,
47+ "/dev/nvidia-uvm-tools" ,
48+ "/dev/nvidia-modeset" ,
49+ "/dev/nvmap" ,
50+ ] ;
51+ GPU_DEVICE_PATHS
52+ . iter ( )
53+ . any ( |path| std:: path:: Path :: new ( path) . exists ( ) )
54+ }
55+
3756/// Handle to a running process.
3857pub struct ProcessHandle {
3958 child : Child ,
@@ -414,26 +433,33 @@ pub fn drop_privileges(policy: &SandboxPolicy) -> Result<()> {
414433 target_os = "redox"
415434 ) ) ) ]
416435 {
436+ let preserve_gpu_groups = has_gpu_devices ( ) ;
417437 // Snapshot the container-level supplemental GIDs (e.g. injected by
418438 // CDI for GPU device access) before initgroups replaces them.
419439 // Exclude GID 0 (root) to avoid inadvertent privilege retention.
420440 let root_gid = nix:: unistd:: Gid :: from_raw ( 0 ) ;
421- let container_gids: Vec < nix:: unistd:: Gid > = nix:: unistd:: getgroups ( )
422- . unwrap_or_default ( )
423- . into_iter ( )
424- . filter ( |& g| g != root_gid)
425- . collect ( ) ;
441+ let container_gids: Vec < nix:: unistd:: Gid > = if preserve_gpu_groups {
442+ nix:: unistd:: getgroups ( )
443+ . unwrap_or_default ( )
444+ . into_iter ( )
445+ . filter ( |& g| g != root_gid)
446+ . collect ( )
447+ } else {
448+ Vec :: new ( )
449+ } ;
426450 nix:: unistd:: initgroups ( user_cstr. as_c_str ( ) , group. gid ) . into_diagnostic ( ) ?;
427- // Merge back any CDI-injected GIDs that initgroups dropped so that
428- // exec'd processes retain access to GPU devices (e.g. /dev/nvmap on
429- // Tegra requires the video GID).
430- let mut merged: Vec < nix:: unistd:: Gid > = nix:: unistd:: getgroups ( ) . unwrap_or_default ( ) ;
431- for gid in container_gids {
432- if !merged. contains ( & gid) {
433- merged. push ( gid) ;
451+ if preserve_gpu_groups {
452+ // Merge back CDI-injected GIDs that initgroups dropped so that
453+ // exec'd processes retain access to GPU devices.
454+ let mut merged: Vec < nix:: unistd:: Gid > =
455+ nix:: unistd:: getgroups ( ) . unwrap_or_default ( ) ;
456+ for gid in container_gids {
457+ if !merged. contains ( & gid) {
458+ merged. push ( gid) ;
459+ }
434460 }
461+ nix:: unistd:: setgroups ( & merged) . into_diagnostic ( ) ?;
435462 }
436- nix:: unistd:: setgroups ( & merged) . into_diagnostic ( ) ?;
437463 }
438464 }
439465
@@ -629,6 +655,28 @@ mod tests {
629655 ) ;
630656 }
631657
658+ #[ cfg( not( any(
659+ target_os = "macos" ,
660+ target_os = "ios" ,
661+ target_os = "haiku" ,
662+ target_os = "redox"
663+ ) ) ) ]
664+ #[ test]
665+ fn has_gpu_devices_detects_present_nodes ( ) {
666+ assert_eq ! (
667+ has_gpu_devices( ) ,
668+ [
669+ "/dev/nvidiactl" ,
670+ "/dev/nvidia-uvm" ,
671+ "/dev/nvidia-uvm-tools" ,
672+ "/dev/nvidia-modeset" ,
673+ "/dev/nvmap" ,
674+ ]
675+ . iter( )
676+ . any( |path| std:: path:: Path :: new( path) . exists( ) )
677+ ) ;
678+ }
679+
632680 #[ tokio:: test]
633681 async fn scrub_sensitive_env_removes_ssh_handshake_secret ( ) {
634682 let mut cmd = Command :: new ( "/usr/bin/env" ) ;
0 commit comments