From 4b2f32fc6553944fe59a9149dac1086e354568a8 Mon Sep 17 00:00:00 2001 From: WGH Date: Tue, 18 Apr 2023 02:16:11 +0300 Subject: [PATCH] Add command-pid member to --json-status-fd In cases where bwrap runs its own additional PID 1 process (e.g. --unshare-pid), child-pid is the PID of that process, not the PID of the user-specified COMMAND. This is inconvenient as the user might want to send e.g. SIGTERM to the command to give it a chance to exit gracefully. Closes #553 Signed-off-by: WGH --- bubblewrap.c | 27 +++++++++++++++++++++++++++ bwrap.xml | 8 ++++++++ 2 files changed, 35 insertions(+) diff --git a/bubblewrap.c b/bubblewrap.c index 9b78a9ae..dd205fd7 100644 --- a/bubblewrap.c +++ b/bubblewrap.c @@ -2654,6 +2654,7 @@ main (int argc, int clone_flags; char *old_cwd = NULL; pid_t pid; + pid_t command_pid; int event_fd = -1; int child_wait_fd = -1; int setup_finished_pipe[] = {-1, -1}; @@ -2665,6 +2666,7 @@ main (int argc, int res UNUSED; cleanup_free char *args_data UNUSED = NULL; int intermediate_pids_sockets[2] = {-1, -1}; + int command_pid_sockets[2] = {-1, -1}; const char *exec_path = NULL; /* Handle --version early on before we try to acquire/drop @@ -2897,6 +2899,14 @@ main (int argc, create_pid_socketpair (intermediate_pids_sockets); } + /* Sometimes we spawn command as immediate child, sometimes we run pid 1, sometimes there are more intermediate pids... + * For simplicity, get pid just before exec'ing command to get the real pid. + **/ + if (opt_json_status_fd != -1) + { + create_pid_socketpair (command_pid_sockets); + } + pid = raw_clone (clone_flags, NULL); if (pid == -1) { @@ -2986,6 +2996,16 @@ main (int argc, /* Ignore res, if e.g. the child died and closed child_wait_fd we don't want to error out here */ close (child_wait_fd); + close (command_pid_sockets[1]); + command_pid = read_pid_from_socket (command_pid_sockets[0]); + close (command_pid_sockets[0]); + + if (opt_json_status_fd != -1) + { + cleanup_free char *output = xasprintf ("{ \"command-pid\": %i }\n", command_pid); + dump_info (opt_json_status_fd, output, TRUE); + } + return monitor_child (event_fd, pid, setup_finished_pipe[0]); } @@ -3344,6 +3364,13 @@ main (int argc, __debug__ (("launch executable %s\n", argv[0])); + if (opt_json_status_fd != -1) + { + close (command_pid_sockets[0]); + send_pid_on_socket (command_pid_sockets[1]); + close (command_pid_sockets[1]); + } + if (proc_fd != -1) close (proc_fd); diff --git a/bwrap.xml b/bwrap.xml index 3bb50820..7cfc070b 100644 --- a/bwrap.xml +++ b/bwrap.xml @@ -452,6 +452,7 @@ Multiple JSON documents are written to FD, one per line ("JSON lines" format). Each line is a single JSON object. + After bwrap has started the child process inside the sandbox, it writes an object with a child-pid member to the (this duplicates the older ). @@ -459,10 +460,17 @@ which bwrap was run. If available, the namespace IDs are also included in the object with the child-pid; again, this duplicates the older . + + Just before COMMAND is exec'ed, the process writes its process ID with a command-pid + member. This process ID is the PID of COMMAND, and it might not match child-pid + mentioned above if bwrap runs additional pid 1 process (e.g. when using + ). + When the child process inside the sandbox exits, bwrap writes an object with an exit-code member, and then closes the . The value corresponding to exit-code is the exit status of the child, in the usual shell encoding (n if it exited normally with status n, or 128+n if it was killed by signal n). + Other members may be added to those objects in future versions of bwrap, and other JSON objects may be added before or after the current objects, so readers must ignore members and objects that they do not understand.