aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2022-01-14 20:19:25 +0100
committerLibravatar smitsohu <smitsohu@gmail.com>2022-01-14 23:58:43 +0100
commitc764520b5aa343c00c3a73633511df039645973c (patch)
treeefa4f9e44786d571079e29e9a0223107893e0822
parentrefactor closing of file descriptors (diff)
downloadfirejail-c764520b5aa343c00c3a73633511df039645973c.tar.gz
firejail-c764520b5aa343c00c3a73633511df039645973c.tar.zst
firejail-c764520b5aa343c00c3a73633511df039645973c.zip
keep-fd option (#4845)
-rw-r--r--contrib/vim/syntax/firejail.vim2
-rw-r--r--src/firejail/dbus.c8
-rw-r--r--src/firejail/firejail.h2
-rw-r--r--src/firejail/join.c5
-rw-r--r--src/firejail/main.c9
-rw-r--r--src/firejail/profile.c9
-rw-r--r--src/firejail/sandbox.c43
-rw-r--r--src/firejail/usage.c1
-rw-r--r--src/include/common.h1
-rw-r--r--src/lib/common.c50
-rw-r--r--src/man/firejail-profile.txt5
-rw-r--r--src/man/firejail.txt20
-rw-r--r--src/zsh_completion/_firejail.in1
13 files changed, 138 insertions, 18 deletions
diff --git a/contrib/vim/syntax/firejail.vim b/contrib/vim/syntax/firejail.vim
index 57c7b371d..714ed8e6e 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
51" 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) 51" 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)
52syn 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 52syn 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
53" 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 53" 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
54syn 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|noprinters|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 54syn match fjCommand /\v(allow-debuggers|allusers|apparmor|caps|deterministic-exit-code|deterministic-shutdown|disable-mnt|ipc-namespace|keep-config-pulse|keep-dev-shm|keep-fd|keep-var-tmp|machine-id|memory-deny-write-execute|netfilter|no3d|noautopulse|nodbus|nodvd|nogroups|noinput|nonewprivs|noprinters|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
55syn match fjCommand /ignore / nextgroup=fjCommand,fjCommandNoCond skipwhite contained 55syn match fjCommand /ignore / nextgroup=fjCommand,fjCommandNoCond skipwhite contained
56syn match fjCommand /caps\.drop / nextgroup=fjCapability,fjAll skipwhite contained 56syn match fjCommand /caps\.drop / nextgroup=fjCapability,fjAll skipwhite contained
57syn match fjCommand /caps\.keep / nextgroup=fjCapability skipwhite contained 57syn match fjCommand /caps\.keep / nextgroup=fjCapability skipwhite contained
diff --git a/src/firejail/dbus.c b/src/firejail/dbus.c
index 12256b833..66738bd4b 100644
--- a/src/firejail/dbus.c
+++ b/src/firejail/dbus.c
@@ -298,10 +298,10 @@ void dbus_proxy_start(void) {
298 errExit("fork"); 298 errExit("fork");
299 if (dbus_proxy_pid == 0) { 299 if (dbus_proxy_pid == 0) {
300 // close open files 300 // close open files
301 int keep_list[2]; 301 int keep[2];
302 keep_list[0] = status_pipe[1]; 302 keep[0] = status_pipe[1];
303 keep_list[1] = args_pipe[0]; 303 keep[1] = args_pipe[0];
304 close_all(keep_list, ARRAY_SIZE(keep_list)); 304 close_all(keep, ARRAY_SIZE(keep));
305 305
306 if (arg_dbus_log_file != NULL) { 306 if (arg_dbus_log_file != NULL) {
307 int output_fd = creat(arg_dbus_log_file, 0666); 307 int output_fd = creat(arg_dbus_log_file, 0666);
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 7314c5350..b1f30bcda 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -161,6 +161,7 @@ typedef struct config_t {
161 161
162#define MAX_PROFILE_IGNORE 32 162#define MAX_PROFILE_IGNORE 32
163 char *profile_ignore[MAX_PROFILE_IGNORE]; 163 char *profile_ignore[MAX_PROFILE_IGNORE];
164 char *keep_fd; // inherit file descriptors to sandbox
164 char *chrootdir; // chroot directory 165 char *chrootdir; // chroot directory
165 char *home_private; // private home directory 166 char *home_private; // private home directory
166 char *home_private_keep; // keep list for private home directory 167 char *home_private_keep; // keep list for private home directory
@@ -352,6 +353,7 @@ extern int arg_nou2f; // --nou2f
352extern int arg_noinput; // --noinput 353extern int arg_noinput; // --noinput
353extern int arg_deterministic_exit_code; // always exit with first child's exit status 354extern int arg_deterministic_exit_code; // always exit with first child's exit status
354extern int arg_deterministic_shutdown; // shut down the sandbox if first child dies 355extern int arg_deterministic_shutdown; // shut down the sandbox if first child dies
356extern int arg_keep_fd_all; // inherit all file descriptors to sandbox
355 357
356typedef enum { 358typedef enum {
357 DBUS_POLICY_ALLOW, // Allow unrestricted access to the bus 359 DBUS_POLICY_ALLOW, // Allow unrestricted access to the bus
diff --git a/src/firejail/join.c b/src/firejail/join.c
index 9fc80d85b..b62a1ca9d 100644
--- a/src/firejail/join.c
+++ b/src/firejail/join.c
@@ -569,11 +569,6 @@ void join(pid_t pid, int argc, char **argv, int index) {
569 dbus_set_system_bus_env(); 569 dbus_set_system_bus_env();
570#endif 570#endif
571 571
572 // set nice and rlimits
573 if (arg_nice)
574 set_nice(cfg.nice);
575 set_rlimits();
576
577 start_application(0, shfd, NULL); 572 start_application(0, shfd, NULL);
578 573
579 __builtin_unreachable(); 574 __builtin_unreachable();
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 09e1a1071..0816afe83 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -149,6 +149,7 @@ int arg_nou2f = 0; // --nou2f
149int arg_noinput = 0; // --noinput 149int arg_noinput = 0; // --noinput
150int arg_deterministic_exit_code = 0; // always exit with first child's exit status 150int arg_deterministic_exit_code = 0; // always exit with first child's exit status
151int arg_deterministic_shutdown = 0; // shut down the sandbox if first child dies 151int arg_deterministic_shutdown = 0; // shut down the sandbox if first child dies
152int arg_keep_fd_all = 0; // inherit all file descriptors to sandbox
152DbusPolicy arg_dbus_user = DBUS_POLICY_ALLOW; // --dbus-user 153DbusPolicy arg_dbus_user = DBUS_POLICY_ALLOW; // --dbus-user
153DbusPolicy arg_dbus_system = DBUS_POLICY_ALLOW; // --dbus-system 154DbusPolicy arg_dbus_system = DBUS_POLICY_ALLOW; // --dbus-system
154const char *arg_dbus_log_file = NULL; 155const char *arg_dbus_log_file = NULL;
@@ -1862,6 +1863,14 @@ int main(int argc, char **argv, char **envp) {
1862 } 1863 }
1863 profile_add_ignore(argv[i] + 9); 1864 profile_add_ignore(argv[i] + 9);
1864 } 1865 }
1866 else if (strncmp(argv[i], "--keep-fd=", 10) == 0) {
1867 if (strcmp(argv[i] + 10, "all") == 0)
1868 arg_keep_fd_all = 1;
1869 else {
1870 const char *add = argv[i] + 10;
1871 profile_list_augment(&cfg.keep_fd, add);
1872 }
1873 }
1865#ifdef HAVE_CHROOT 1874#ifdef HAVE_CHROOT
1866 else if (strncmp(argv[i], "--chroot=", 9) == 0) { 1875 else if (strncmp(argv[i], "--chroot=", 9) == 0) {
1867 if (checkcfg(CFG_CHROOT)) { 1876 if (checkcfg(CFG_CHROOT)) {
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 5725100e4..794668dc6 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -290,6 +290,15 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
290 return 0; 290 return 0;
291 } 291 }
292 292
293 if (strncmp(ptr, "keep-fd ", 8) == 0) {
294 if (strcmp(ptr + 8, "all") == 0)
295 arg_keep_fd_all = 1;
296 else {
297 const char *add = ptr + 8;
298 profile_list_augment(&cfg.keep_fd, add);
299 }
300 return 0;
301 }
293 if (strncmp(ptr, "xephyr-screen ", 14) == 0) { 302 if (strncmp(ptr, "xephyr-screen ", 14) == 0) {
294#ifdef HAVE_X11 303#ifdef HAVE_X11
295 if (checkcfg(CFG_X11)) { 304 if (checkcfg(CFG_X11)) {
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 61d6578a0..0e4e1a36e 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -399,12 +399,28 @@ static int monitor_application(pid_t app_pid) {
399 return arg_deterministic_exit_code ? app_status : status; 399 return arg_deterministic_exit_code ? app_status : status;
400} 400}
401 401
402
402static void print_time(void) { 403static void print_time(void) {
403 float delta = timetrace_end(); 404 float delta = timetrace_end();
404 fmessage("Child process initialized in %.02f ms\n", delta); 405 fmessage("Child process initialized in %.02f ms\n", delta);
405} 406}
406 407
407 408
409int *build_keep_fd_array(size_t *sz) {
410 if (!cfg.keep_fd) {
411 *sz = 0;
412 return NULL;
413 }
414
415 int *rv = str_to_int_array(cfg.keep_fd, sz);
416 if (!rv) {
417 fprintf(stderr, "Error: invalid keep-fd option\n");
418 exit(1);
419 }
420 return rv;
421}
422
423
408// check execute permissions for the program 424// check execute permissions for the program
409// this is done typically by the shell 425// this is done typically by the shell
410// we are here because of --shell=none 426// we are here because of --shell=none
@@ -461,10 +477,27 @@ static int ok_to_run(const char *program) {
461 return 0; 477 return 0;
462} 478}
463 479
480
464void start_application(int no_sandbox, int fd, char *set_sandbox_status) { 481void start_application(int no_sandbox, int fd, char *set_sandbox_status) {
465 // set environment 482 if (no_sandbox == 0) {
466 if (no_sandbox == 0) 483 // don't leak open file descriptors
484 if (!arg_keep_fd_all) {
485 size_t sz;
486 int *keep = build_keep_fd_array(&sz);
487 close_all(keep, sz);
488 if (keep)
489 free(keep);
490 }
491
492 // set nice and rlimits
493 if (arg_nice)
494 set_nice(cfg.nice);
495 set_rlimits();
496
467 env_defaults(); 497 env_defaults();
498 }
499
500 // set environment
468 env_apply_all(); 501 env_apply_all();
469 502
470 // restore original umask 503 // restore original umask
@@ -1252,12 +1285,6 @@ int sandbox(void* sandbox_arg) {
1252#ifdef HAVE_APPARMOR 1285#ifdef HAVE_APPARMOR
1253 set_apparmor(); 1286 set_apparmor();
1254#endif 1287#endif
1255
1256 // set nice and rlimits
1257 if (arg_nice)
1258 set_nice(cfg.nice);
1259 set_rlimits();
1260
1261 start_application(0, -1, set_sandbox_status); 1288 start_application(0, -1, set_sandbox_status);
1262 } 1289 }
1263 1290
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index 24c8e3194..c903841c5 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -119,6 +119,7 @@ static char *usage_str =
119 " --join-or-start=name|pid - join the sandbox or start a new one.\n" 119 " --join-or-start=name|pid - join the sandbox or start a new one.\n"
120 " --keep-config-pulse - disable automatic ~/.config/pulse init.\n" 120 " --keep-config-pulse - disable automatic ~/.config/pulse init.\n"
121 " --keep-dev-shm - /dev/shm directory is untouched (even with --private-dev).\n" 121 " --keep-dev-shm - /dev/shm directory is untouched (even with --private-dev).\n"
122 " --keep-fd - inherit open file descriptors to sandbox.\n"
122 " --keep-var-tmp - /var/tmp directory is untouched.\n" 123 " --keep-var-tmp - /var/tmp directory is untouched.\n"
123 " --list - list all sandboxes.\n" 124 " --list - list all sandboxes.\n"
124#ifdef HAVE_FILE_TRANSFER 125#ifdef HAVE_FILE_TRANSFER
diff --git a/src/include/common.h b/src/include/common.h
index 24feab02a..f72ec9738 100644
--- a/src/include/common.h
+++ b/src/include/common.h
@@ -142,4 +142,5 @@ int pid_proc_cmdline_x11_xpra_xephyr(const pid_t pid);
142int pid_hidepid(void); 142int pid_hidepid(void);
143void warn_dumpable(void); 143void warn_dumpable(void);
144const char *gnu_basename(const char *path); 144const char *gnu_basename(const char *path);
145int *str_to_int_array(const char *str, size_t *sz);
145#endif 146#endif
diff --git a/src/lib/common.c b/src/lib/common.c
index f46e7db1c..91d5125b1 100644
--- a/src/lib/common.c
+++ b/src/lib/common.c
@@ -31,6 +31,7 @@
31#include <dirent.h> 31#include <dirent.h>
32#include <string.h> 32#include <string.h>
33#include <time.h> 33#include <time.h>
34#include <limits.h>
34#include "../include/common.h" 35#include "../include/common.h"
35#define BUFLEN 4096 36#define BUFLEN 4096
36 37
@@ -320,6 +321,55 @@ const char *gnu_basename(const char *path) {
320 return last_slash+1; 321 return last_slash+1;
321} 322}
322 323
324// takes string with comma separated int values, returns int array
325int *str_to_int_array(const char *str, size_t *sz) {
326 assert(str && sz);
327
328 size_t curr_sz = 0;
329 size_t arr_sz = 16;
330 int *rv = malloc(arr_sz * sizeof(int));
331 if (!rv)
332 errExit("malloc");
333
334 char *dup = strdup(str);
335 if (!dup)
336 errExit("strdup");
337 char *tok = strtok(dup, ",");
338 if (!tok) {
339 free(dup);
340 free(rv);
341 goto errout;
342 }
343
344 while (tok) {
345 char *end;
346 long val = strtol(tok, &end, 10);
347 if (end == tok || *end != '\0' || val < INT_MIN || val > INT_MAX) {
348 free(dup);
349 free(rv);
350 goto errout;
351 }
352
353 if (curr_sz == arr_sz) {
354 arr_sz *= 2;
355 rv = realloc(rv, arr_sz * sizeof(int));
356 if (!rv)
357 errExit("realloc");
358 }
359 rv[curr_sz++] = val;
360
361 tok = strtok(NULL, ",");
362 }
363 free(dup);
364
365 *sz = curr_sz;
366 return rv;
367
368errout:
369 *sz = 0;
370 return NULL;
371}
372
323//************************** 373//**************************
324// time trace based on getticks function 374// time trace based on getticks function
325//************************** 375//**************************
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt
index 71dab18ba..29f0fe4e4 100644
--- a/src/man/firejail-profile.txt
+++ b/src/man/firejail-profile.txt
@@ -724,6 +724,11 @@ env CFLAGS="-W -Wall -Werror"
724.TP 724.TP
725\fBipc-namespace 725\fBipc-namespace
726Enable IPC namespace. 726Enable IPC namespace.
727
728.TP
729\fBkeep-fd
730Inherit open file descriptors to sandbox.
731
727.TP 732.TP
728\fBname sandboxname 733\fBname sandboxname
729Set sandbox name. Example: 734Set sandbox name. Example:
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 80487a49d..a5704e995 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -1104,6 +1104,26 @@ Example:
1104$ firejail --keep-dev-shm --private-dev 1104$ firejail --keep-dev-shm --private-dev
1105 1105
1106.TP 1106.TP
1107\fB\-\-keep-fd=all
1108Inherit all open file descriptors to the sandbox. By default only file descriptors 0, 1 and 2 are inherited to the sandbox, and all other file descriptors are closed.
1109.br
1110
1111.br
1112Example:
1113.br
1114$ firejail --keep-fd=all
1115
1116.TP
1117\fB\-\-keep-fd=file_descriptor
1118Don't close specified open file descriptors. By default only file descriptors 0, 1 and 2 are inherited to the sandbox, and all other file descriptors are closed.
1119.br
1120
1121.br
1122Example:
1123.br
1124$ firejail --keep-fd=3,4,5
1125
1126.TP
1107\fB\-\-keep-var-tmp 1127\fB\-\-keep-var-tmp
1108/var/tmp directory is untouched. 1128/var/tmp directory is untouched.
1109.br 1129.br
diff --git a/src/zsh_completion/_firejail.in b/src/zsh_completion/_firejail.in
index 334812dd6..f7cd3cdff 100644
--- a/src/zsh_completion/_firejail.in
+++ b/src/zsh_completion/_firejail.in
@@ -104,6 +104,7 @@ _firejail_args=(
104 '--join-or-start=-[join the sandbox or start a new one name|pid]: :_all_firejails' 104 '--join-or-start=-[join the sandbox or start a new one name|pid]: :_all_firejails'
105 '--keep-config-pulse[disable automatic ~/.config/pulse init]' 105 '--keep-config-pulse[disable automatic ~/.config/pulse init]'
106 '--keep-dev-shm[/dev/shm directory is untouched (even with --private-dev)]' 106 '--keep-dev-shm[/dev/shm directory is untouched (even with --private-dev)]'
107 '--keep-fd[inherit open file descriptors to sandbox]'
107 '--keep-var-tmp[/var/tmp directory is untouched]' 108 '--keep-var-tmp[/var/tmp directory is untouched]'
108 '--machine-id[spoof /etc/machine-id with a random id]' 109 '--machine-id[spoof /etc/machine-id with a random id]'
109 '--memory-deny-write-execute[seccomp filter to block attempts to create memory mappings that are both writable and executable]' 110 '--memory-deny-write-execute[seccomp filter to block attempts to create memory mappings that are both writable and executable]'