@@ -8,7 +8,7 @@ use std::os::unix::fs::PermissionsExt;
88use std:: os:: unix:: io:: AsRawFd ;
99use std:: os:: unix:: process:: CommandExt ;
1010use std:: path:: { Component , Path , PathBuf } ;
11- use std:: process:: { Command , Stdio } ;
11+ use std:: process:: { exit , Command , Stdio } ;
1212use std:: { fmt, io} ;
1313
1414use utils:: arg_parser:: Error :: MissingValue ;
@@ -674,12 +674,45 @@ impl Env {
674674
675675 // Daemonize before exec, if so required (when the dev_null variable != None).
676676 if let Some ( dev_null) = dev_null {
677- // Call setsid().
677+ // We follow the double fork method to daemonize the jailer referring to
678+ // https://0xjet.github.io/3OHA/2022/04/11/post.html
679+ // setsid() will fail if the calling process is a process group leader.
680+ // By calling fork(), we guarantee that the newly created process inherits
681+ // the PGID from its parent and, therefore, is not a process group leader.
682+ // SAFETY: Safe because it's a library function.
683+ let child_pid = unsafe { libc:: fork ( ) } ;
684+ if child_pid < 0 {
685+ return Err ( JailerError :: Daemonize ( io:: Error :: last_os_error ( ) ) ) ;
686+ }
687+
688+ if child_pid != 0 {
689+ // parent exiting
690+ exit ( 0 ) ;
691+ }
692+
693+ // Call setsid() in child
678694 // SAFETY: Safe because it's a library function.
679695 SyscallReturnCode ( unsafe { libc:: setsid ( ) } )
680696 . into_empty_result ( )
681697 . map_err ( JailerError :: SetSid ) ?;
682698
699+ // Daemons should not have controlling terminals.
700+ // If a daemon has a controlling terminal, it can receive signals
701+ // from it that might cause it to halt or exit unexpectedly.
702+ // The second fork() ensures that grandchild is not a session,
703+ // leader and thus cannot reacquire a controlling terminal.
704+ // SAFETY: Safe because it's a library function.
705+ let grandchild_pid = unsafe { libc:: fork ( ) } ;
706+ if grandchild_pid < 0 {
707+ return Err ( JailerError :: Daemonize ( io:: Error :: last_os_error ( ) ) ) ;
708+ }
709+
710+ if grandchild_pid != 0 {
711+ // child exiting
712+ exit ( 0 ) ;
713+ }
714+
715+ // grandchild is the daemon
683716 // Replace the stdio file descriptors with the /dev/null fd.
684717 dup2 ( dev_null. as_raw_fd ( ) , STDIN_FILENO ) ?;
685718 dup2 ( dev_null. as_raw_fd ( ) , STDOUT_FILENO ) ?;
0 commit comments