@@ -8,7 +8,7 @@ use std::os::unix::fs::PermissionsExt;
8
8
use std:: os:: unix:: io:: AsRawFd ;
9
9
use std:: os:: unix:: process:: CommandExt ;
10
10
use std:: path:: { Component , Path , PathBuf } ;
11
- use std:: process:: { Command , Stdio } ;
11
+ use std:: process:: { exit , Command , Stdio } ;
12
12
use std:: { fmt, io} ;
13
13
14
14
use utils:: arg_parser:: Error :: MissingValue ;
@@ -674,12 +674,45 @@ impl Env {
674
674
675
675
// Daemonize before exec, if so required (when the dev_null variable != None).
676
676
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
678
694
// SAFETY: Safe because it's a library function.
679
695
SyscallReturnCode ( unsafe { libc:: setsid ( ) } )
680
696
. into_empty_result ( )
681
697
. map_err ( JailerError :: SetSid ) ?;
682
698
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
683
716
// Replace the stdio file descriptors with the /dev/null fd.
684
717
dup2 ( dev_null. as_raw_fd ( ) , STDIN_FILENO ) ?;
685
718
dup2 ( dev_null. as_raw_fd ( ) , STDOUT_FILENO ) ?;
0 commit comments