@@ -623,72 +623,45 @@ impl Jail for LinuxJail {
623623
624624 // Check if we're running as root and should drop privileges
625625 let current_uid = unsafe { libc:: getuid ( ) } ;
626- let target_user = if current_uid == 0 {
627- // Running as root - check for SUDO_USER to drop privileges to original user
628- std:: env:: var ( "SUDO_USER" ) . ok ( )
626+ let drop_privs = if current_uid == 0 {
627+ // Running as root - check for SUDO_UID/SUDO_GID to drop privileges to original user
628+ match ( std:: env:: var ( "SUDO_UID" ) , std:: env:: var ( "SUDO_GID" ) ) {
629+ ( Ok ( uid) , Ok ( gid) ) => {
630+ debug ! (
631+ "Will drop privileges to uid={} gid={} after entering namespace" ,
632+ uid, gid
633+ ) ;
634+ Some ( ( uid, gid) )
635+ }
636+ _ => {
637+ debug ! ( "Running as root but no SUDO_UID/SUDO_GID found, continuing as root" ) ;
638+ None
639+ }
640+ }
629641 } else {
630642 // Not root - no privilege dropping needed
631643 None
632644 } ;
633645
634- if let Some ( ref user) = target_user {
635- debug ! (
636- "Will drop to user '{}' (from SUDO_USER) after entering namespace" ,
637- user
638- ) ;
639- }
640-
641646 // Build command: ip netns exec <namespace> <command>
642- // If we need to drop privileges, we wrap with su
647+ // If we need to drop privileges, we wrap with setpriv
643648 let mut cmd = Command :: new ( "ip" ) ;
644649 cmd. args ( [ "netns" , "exec" , & self . namespace_name ( ) ] ) ;
645650
646- // When we have environment variables to pass OR need to drop privileges,
647- // use a shell wrapper to ensure proper environment handling
648- if target_user. is_some ( ) || !extra_env. is_empty ( ) {
649- // Build shell command with explicit environment exports
650- let mut shell_command = String :: new ( ) ;
651-
652- // Export environment variables explicitly in the shell command
653- for ( key, value) in extra_env {
654- // Escape the value for shell safety
655- let escaped_value = value. replace ( '\'' , "'\\ ''" ) ;
656- shell_command. push_str ( & format ! ( "export {}='{}'; " , key, escaped_value) ) ;
657- }
658-
659- // Add the actual command with proper escaping
660- shell_command. push_str (
661- & command
662- . iter ( )
663- . map ( |arg| {
664- // Simple escaping: wrap in single quotes and escape existing single quotes
665- if arg. contains ( '\'' ) {
666- format ! ( "\" {}\" " , arg. replace( '"' , "\\ \" " ) )
667- } else {
668- format ! ( "'{}'" , arg)
669- }
670- } )
671- . collect :: < Vec < _ > > ( )
672- . join ( " " ) ,
673- ) ;
674-
675- if let Some ( user) = target_user {
676- // Use su to drop privileges to the original user
677- cmd. arg ( "su" ) ;
678- cmd. arg ( "-s" ) ; // Specify shell explicitly
679- cmd. arg ( "/bin/sh" ) ; // Use sh for compatibility
680- cmd. arg ( "-p" ) ; // Preserve environment
681- cmd. arg ( & user) ; // Username from SUDO_USER
682- cmd. arg ( "-c" ) ; // Execute command
683- cmd. arg ( shell_command) ;
684- } else {
685- // No privilege dropping but need shell for env vars
686- cmd. arg ( "sh" ) ;
687- cmd. arg ( "-c" ) ;
688- cmd. arg ( shell_command) ;
651+ // Handle privilege dropping and command execution
652+ if let Some ( ( uid, gid) ) = drop_privs {
653+ // Use setpriv to drop privileges to the original user
654+ // setpriv is lighter than runuser - no PAM, direct execve()
655+ cmd. arg ( "setpriv" ) ;
656+ cmd. arg ( format ! ( "--reuid={}" , uid) ) ; // Set real and effective UID
657+ cmd. arg ( format ! ( "--regid={}" , gid) ) ; // Set real and effective GID
658+ cmd. arg ( "--init-groups" ) ; // Initialize supplementary groups
659+ cmd. arg ( "--" ) ; // End of options
660+ for arg in command {
661+ cmd. arg ( arg) ;
689662 }
690663 } else {
691- // No privilege dropping and no env vars , execute directly
664+ // No privilege dropping, execute directly
692665 cmd. arg ( & command[ 0 ] ) ;
693666 for arg in & command[ 1 ..] {
694667 cmd. arg ( arg) ;
@@ -711,6 +684,8 @@ impl Jail for LinuxJail {
711684 cmd. env ( "SUDO_GID" , sudo_gid) ;
712685 }
713686
687+ debug ! ( "Executing command: {:?}" , cmd) ;
688+
714689 // Note: We do NOT set HTTP_PROXY/HTTPS_PROXY environment variables here.
715690 // The jail uses nftables rules to transparently redirect traffic to the proxy,
716691 // making it work with applications that don't respect proxy environment variables.
0 commit comments