From e20960ab4561f1cb97c69114f56b19b48db311c3 Mon Sep 17 00:00:00 2001 From: smitsohu Date: Sun, 24 Oct 2021 16:46:28 +0200 Subject: [PATCH] deterministic-shutdown option --- contrib/vim/syntax/firejail.vim | 2 +- etc/profile-a-l/akregator.profile | 1 + etc/profile-a-l/default.profile | 1 + etc/profile-a-l/dillo.profile | 2 ++ etc/profile-a-l/ktorrent.profile | 1 + etc/profile-m-z/server.profile | 1 + etc/templates/profile.template | 1 + src/firejail/firejail.h | 1 + src/firejail/main.c | 4 ++++ src/firejail/profile.c | 5 +++++ src/firejail/sandbox.c | 21 +++++++++------------ src/firejail/usage.c | 1 + src/man/firejail-profile.txt | 5 +++++ src/man/firejail.txt | 6 ++++++ src/zsh_completion/_firejail.in | 1 + 15 files changed, 40 insertions(+), 13 deletions(-) diff --git a/contrib/vim/syntax/firejail.vim b/contrib/vim/syntax/firejail.vim index fa80a9c0062..bcaa85a9c37 100644 --- a/contrib/vim/syntax/firejail.vim +++ b/contrib/vim/syntax/firejail.vim @@ -51,7 +51,7 @@ syn match fjVar /\v\$\{(CFG|DESKTOP|DOCUMENTS|DOWNLOADS|HOME|MUSIC|PATH|PICTURES " Generate list with: { rg -o 'strn?cmp\(ptr, "([^"]+) "' -r '$1' src/firejail/profile.c; echo private-lib; } | grep -vEx '(include|ignore|caps\.drop|caps\.keep|protocol|seccomp|seccomp\.drop|seccomp\.keep|env|rmenv|net|ip)' | sort -u | tr $'\n' '|' # private-lib is special-cased in the code and doesn't match the regex; grep-ed patterns are handled later with 'syn match nextgroup=' directives (except for include which is special-cased as a fjCommandNoCond keyword) syn match fjCommand /\v(bind|blacklist|blacklist-nolog|cgroup|cpu|defaultgw|dns|hostname|hosts-file|ip6|iprange|join-or-start|mac|mkdir|mkfile|mtu|name|netfilter|netfilter6|netmask|nice|noblacklist|noexec|nowhitelist|overlay-named|private|private-bin|private-cwd|private-etc|private-home|private-lib|private-opt|private-srv|read-only|read-write|rlimit-as|rlimit-cpu|rlimit-fsize|rlimit-nofile|rlimit-nproc|rlimit-sigpending|timeout|tmpfs|veth-name|whitelist|xephyr-screen) / skipwhite contained " Generate list with: rg -o 'strn?cmp\(ptr, "([^ "]*[^ ])"' -r '$1' src/firejail/profile.c | grep -vEx '(include|rlimit|quiet)' | sed -e 's/\./\\./' | sort -u | tr $'\n' '|' # include/rlimit are false positives, quiet is special-cased below -syn match fjCommand /\v(allow-debuggers|allusers|apparmor|caps|disable-mnt|ipc-namespace|keep-config-pulse|keep-dev-shm|keep-var-tmp|machine-id|memory-deny-write-execute|netfilter|no3d|noautopulse|nodbus|nodvd|nogroups|noinput|nonewprivs|noroot|nosound|notv|nou2f|novideo|overlay|overlay-tmpfs|private|private-cache|private-cwd|private-dev|private-lib|private-tmp|seccomp|seccomp\.32|seccomp\.block-secondary|tracelog|writable-etc|writable-run-user|writable-var|writable-var-log|x11)$/ contained +syn match fjCommand /\v(allow-debuggers|allusers|apparmor|caps|deterministic-exit-code|deterministic-shutdown|disable-mnt|ipc-namespace|keep-config-pulse|keep-dev-shm|keep-var-tmp|machine-id|memory-deny-write-execute|netfilter|no3d|noautopulse|nodbus|nodvd|nogroups|noinput|nonewprivs|noroot|nosound|notv|nou2f|novideo|overlay|overlay-tmpfs|private|private-cache|private-cwd|private-dev|private-lib|private-tmp|seccomp|seccomp\.32|seccomp\.block-secondary|tracelog|writable-etc|writable-run-user|writable-var|writable-var-log|x11)$/ contained syn match fjCommand /ignore / nextgroup=fjCommand,fjCommandNoCond skipwhite contained syn match fjCommand /caps\.drop / nextgroup=fjCapability,fjAll skipwhite contained syn match fjCommand /caps\.keep / nextgroup=fjCapability skipwhite contained diff --git a/etc/profile-a-l/akregator.profile b/etc/profile-a-l/akregator.profile index 39008d67a12..47468a65878 100644 --- a/etc/profile-a-l/akregator.profile +++ b/etc/profile-a-l/akregator.profile @@ -49,3 +49,4 @@ private-bin akregator,akregatorstorageexporter,dbus-launch,kdeinit4,kdeinit4_shu private-dev private-tmp +deterministic-shutdown diff --git a/etc/profile-a-l/default.profile b/etc/profile-a-l/default.profile index 0d8c224d7eb..dac842bb679 100644 --- a/etc/profile-a-l/default.profile +++ b/etc/profile-a-l/default.profile @@ -57,5 +57,6 @@ seccomp # dbus-user none # dbus-system none +# deterministic-shutdown # memory-deny-write-execute # read-only ${HOME} diff --git a/etc/profile-a-l/dillo.profile b/etc/profile-a-l/dillo.profile index 276ee251a13..19b99b5fd4f 100644 --- a/etc/profile-a-l/dillo.profile +++ b/etc/profile-a-l/dillo.profile @@ -35,3 +35,5 @@ tracelog private-dev private-tmp + +deterministic-shutdown diff --git a/etc/profile-a-l/ktorrent.profile b/etc/profile-a-l/ktorrent.profile index 6e3b0c8757e..f3eae678092 100644 --- a/etc/profile-a-l/ktorrent.profile +++ b/etc/profile-a-l/ktorrent.profile @@ -62,4 +62,5 @@ private-dev # private-lib - problems on Arch private-tmp +deterministic-shutdown # memory-deny-write-execute diff --git a/etc/profile-m-z/server.profile b/etc/profile-m-z/server.profile index 3c9ef3a8676..9e40796a6f4 100644 --- a/etc/profile-m-z/server.profile +++ b/etc/profile-m-z/server.profile @@ -83,6 +83,7 @@ private-tmp dbus-user none # dbus-system none +# deterministic-shutdown # memory-deny-write-execute # read-only ${HOME} # writable-run-user diff --git a/etc/templates/profile.template b/etc/templates/profile.template index 44197b5472c..1a4c8fef9a5 100644 --- a/etc/templates/profile.template +++ b/etc/templates/profile.template @@ -220,6 +220,7 @@ include globals.local #dbus-user.talk org.freedesktop.Notifications #dbus-system none +##deterministic-shutdown ##env VAR=VALUE ##join-or-start NAME #memory-deny-write-execute diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index ec789cd63e6..adfe77f4139 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -350,6 +350,7 @@ extern int arg_nodvd; // --nodvd extern int arg_nou2f; // --nou2f extern int arg_noinput; // --noinput extern int arg_deterministic_exit_code; // always exit with first child's exit status +extern int arg_deterministic_shutdown; // shut down the sandbox if first child dies typedef enum { DBUS_POLICY_ALLOW, // Allow unrestricted access to the bus diff --git a/src/firejail/main.c b/src/firejail/main.c index 1ba70b0bdef..4bcf98035d9 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -147,6 +147,7 @@ int arg_nodvd = 0; // --nodvd int arg_nou2f = 0; // --nou2f int arg_noinput = 0; // --noinput int arg_deterministic_exit_code = 0; // always exit with first child's exit status +int arg_deterministic_shutdown = 0; // shut down the sandbox if first child dies DbusPolicy arg_dbus_user = DBUS_POLICY_ALLOW; // --dbus-user DbusPolicy arg_dbus_system = DBUS_POLICY_ALLOW; // --dbus-system const char *arg_dbus_log_file = NULL; @@ -2765,6 +2766,9 @@ int main(int argc, char **argv, char **envp) { else if (strcmp(argv[i], "--deterministic-exit-code") == 0) { arg_deterministic_exit_code = 1; } + else if (strcmp(argv[i], "--deterministic-shutdown") == 0) { + arg_deterministic_shutdown = 1; + } else { // double dash - positional params to follow if (strcmp(argv[i], "--") == 0) { diff --git a/src/firejail/profile.c b/src/firejail/profile.c index babc3941e55..d44b97ff632 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c @@ -1597,6 +1597,11 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { return 0; } + if (strcmp(ptr, "deterministic-shutdown") == 0) { + arg_deterministic_shutdown = 1; + return 0; + } + // rest of filesystem if (strncmp(ptr, "blacklist ", 10) == 0) ptr += 10; diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index efa21c34bea..3887b570151 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c @@ -356,6 +356,15 @@ static int monitor_application(pid_t app_pid) { if (arg_debug) printf("Sandbox monitor: waitpid %d retval %d status %d\n", monitored_pid, rv, status); + if (arg_deterministic_shutdown) { + if (arg_debug) + printf("Sandbox monitor: monitored process died, shut down the sandbox\n"); + kill(-1, SIGTERM); + usleep(100000); + kill(-1, SIGKILL); + break; + } + DIR *dir; if (!(dir = opendir("/proc"))) { // sleep 2 seconds and try again @@ -377,18 +386,6 @@ static int monitor_application(pid_t app_pid) { if ((pid_t) pid == dhclient4_pid || (pid_t) pid == dhclient6_pid) continue; - // todo: make this generic - // Dillo browser leaves a dpid process running, we need to shut it down - int found = 0; - if (strcmp(cfg.command_name, "dillo") == 0) { - char *pidname = pid_proc_comm(pid); - if (pidname && strcmp(pidname, "dpid") == 0) - found = 1; - free(pidname); - } - if (found) - break; - monitored_pid = pid; break; } diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 43f862b9d7d..92806d3f15d 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c @@ -87,6 +87,7 @@ static char *usage_str = " --defaultgw=address - configure default gateway.\n" #endif " --deterministic-exit-code - always exit with first child's status code.\n" + " --deterministic-shutdown - terminate orphan processes.\n" " --dns=address - set DNS server.\n" " --dns.print=name|pid - print DNS configuration.\n" " --env=name=value - set environment variable.\n" diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index a1eccaa5eab..f6c905d595e 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt @@ -954,11 +954,16 @@ be created and configured using "ip netns". Use this name for the interface connected to the bridge for --net=bridge_interface commands, instead of the default one. #endif + .SH Other .TP \fBdeterministic-exit-code Always exit firejail with the first child's exit status. The default behavior is to use the exit status of the final child to exit, which can be nondeterministic. +.TP +\fBdeterministic-shutdown +Always shut down the sandbox after the first child has terminated. The default behavior is to keep the sandbox alive as long as it contains running processes. + .TP \fBjoin-or-start sandboxname Join the sandbox identified by name or start a new one. diff --git a/src/man/firejail.txt b/src/man/firejail.txt index e724e4bb946..49933926464 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt @@ -706,6 +706,12 @@ $ firejail \-\-net=eth0 \-\-defaultgw=10.10.20.1 firefox \fB\-\-deterministic-exit-code Always exit firejail with the first child's exit status. The default behavior is to use the exit status of the final child to exit, which can be nondeterministic. .br + +.TP +\fB\-\-deterministic-shutdown +Always shut down the sandbox after the first child has terminated. The default behavior is to keep the sandbox alive as long as it contains running processes. +.br + .TP \fB\-\-disable-mnt Blacklist /mnt, /media, /run/mount and /run/media access. diff --git a/src/zsh_completion/_firejail.in b/src/zsh_completion/_firejail.in index c7f6ee3f11b..b50c5cb4690 100644 --- a/src/zsh_completion/_firejail.in +++ b/src/zsh_completion/_firejail.in @@ -94,6 +94,7 @@ _firejail_args=( '--cpu=-[set cpu affinity]: :->cpus' '*--deny=-[deny access to directory or file]: :_files' "--deterministic-exit-code[always exit with first child's status code]" + '--deterministic-shutdown[terminate orphan processes]' '*--dns=-[set DNS server]: :' '*--env=-[set environment variable]: :' '--hostname=-[set sandbox hostname]: :'