Skip to content

Commit

Permalink
keep-fd option (#4845)
Browse files Browse the repository at this point in the history
  • Loading branch information
smitsohu committed Jan 14, 2022
1 parent 4efbd78 commit c764520
Show file tree
Hide file tree
Showing 13 changed files with 138 additions and 18 deletions.
2 changes: 1 addition & 1 deletion contrib/vim/syntax/firejail.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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|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
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-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
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
Expand Down
8 changes: 4 additions & 4 deletions src/firejail/dbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,10 +298,10 @@ void dbus_proxy_start(void) {
errExit("fork");
if (dbus_proxy_pid == 0) {
// close open files
int keep_list[2];
keep_list[0] = status_pipe[1];
keep_list[1] = args_pipe[0];
close_all(keep_list, ARRAY_SIZE(keep_list));
int keep[2];
keep[0] = status_pipe[1];
keep[1] = args_pipe[0];
close_all(keep, ARRAY_SIZE(keep));

if (arg_dbus_log_file != NULL) {
int output_fd = creat(arg_dbus_log_file, 0666);
Expand Down
2 changes: 2 additions & 0 deletions src/firejail/firejail.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ typedef struct config_t {

#define MAX_PROFILE_IGNORE 32
char *profile_ignore[MAX_PROFILE_IGNORE];
char *keep_fd; // inherit file descriptors to sandbox
char *chrootdir; // chroot directory
char *home_private; // private home directory
char *home_private_keep; // keep list for private home directory
Expand Down Expand Up @@ -352,6 +353,7 @@ 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
extern int arg_keep_fd_all; // inherit all file descriptors to sandbox

typedef enum {
DBUS_POLICY_ALLOW, // Allow unrestricted access to the bus
Expand Down
5 changes: 0 additions & 5 deletions src/firejail/join.c
Original file line number Diff line number Diff line change
Expand Up @@ -569,11 +569,6 @@ void join(pid_t pid, int argc, char **argv, int index) {
dbus_set_system_bus_env();
#endif

// set nice and rlimits
if (arg_nice)
set_nice(cfg.nice);
set_rlimits();

start_application(0, shfd, NULL);

__builtin_unreachable();
Expand Down
9 changes: 9 additions & 0 deletions src/firejail/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ 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
int arg_keep_fd_all = 0; // inherit all file descriptors to sandbox
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;
Expand Down Expand Up @@ -1862,6 +1863,14 @@ int main(int argc, char **argv, char **envp) {
}
profile_add_ignore(argv[i] + 9);
}
else if (strncmp(argv[i], "--keep-fd=", 10) == 0) {
if (strcmp(argv[i] + 10, "all") == 0)
arg_keep_fd_all = 1;
else {
const char *add = argv[i] + 10;
profile_list_augment(&cfg.keep_fd, add);
}
}
#ifdef HAVE_CHROOT
else if (strncmp(argv[i], "--chroot=", 9) == 0) {
if (checkcfg(CFG_CHROOT)) {
Expand Down
9 changes: 9 additions & 0 deletions src/firejail/profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,15 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
return 0;
}

if (strncmp(ptr, "keep-fd ", 8) == 0) {
if (strcmp(ptr + 8, "all") == 0)
arg_keep_fd_all = 1;
else {
const char *add = ptr + 8;
profile_list_augment(&cfg.keep_fd, add);
}
return 0;
}
if (strncmp(ptr, "xephyr-screen ", 14) == 0) {
#ifdef HAVE_X11
if (checkcfg(CFG_X11)) {
Expand Down
43 changes: 35 additions & 8 deletions src/firejail/sandbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,12 +399,28 @@ static int monitor_application(pid_t app_pid) {
return arg_deterministic_exit_code ? app_status : status;
}


static void print_time(void) {
float delta = timetrace_end();
fmessage("Child process initialized in %.02f ms\n", delta);
}


int *build_keep_fd_array(size_t *sz) {
if (!cfg.keep_fd) {
*sz = 0;
return NULL;
}

int *rv = str_to_int_array(cfg.keep_fd, sz);
if (!rv) {
fprintf(stderr, "Error: invalid keep-fd option\n");
exit(1);
}
return rv;
}


// check execute permissions for the program
// this is done typically by the shell
// we are here because of --shell=none
Expand Down Expand Up @@ -461,10 +477,27 @@ static int ok_to_run(const char *program) {
return 0;
}


void start_application(int no_sandbox, int fd, char *set_sandbox_status) {
// set environment
if (no_sandbox == 0)
if (no_sandbox == 0) {
// don't leak open file descriptors
if (!arg_keep_fd_all) {
size_t sz;
int *keep = build_keep_fd_array(&sz);
close_all(keep, sz);
if (keep)
free(keep);
}

// set nice and rlimits
if (arg_nice)
set_nice(cfg.nice);
set_rlimits();

env_defaults();
}

// set environment
env_apply_all();

// restore original umask
Expand Down Expand Up @@ -1252,12 +1285,6 @@ int sandbox(void* sandbox_arg) {
#ifdef HAVE_APPARMOR
set_apparmor();
#endif

// set nice and rlimits
if (arg_nice)
set_nice(cfg.nice);
set_rlimits();

start_application(0, -1, set_sandbox_status);
}

Expand Down
1 change: 1 addition & 0 deletions src/firejail/usage.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ static char *usage_str =
" --join-or-start=name|pid - join the sandbox or start a new one.\n"
" --keep-config-pulse - disable automatic ~/.config/pulse init.\n"
" --keep-dev-shm - /dev/shm directory is untouched (even with --private-dev).\n"
" --keep-fd - inherit open file descriptors to sandbox.\n"
" --keep-var-tmp - /var/tmp directory is untouched.\n"
" --list - list all sandboxes.\n"
#ifdef HAVE_FILE_TRANSFER
Expand Down
1 change: 1 addition & 0 deletions src/include/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,5 @@ int pid_proc_cmdline_x11_xpra_xephyr(const pid_t pid);
int pid_hidepid(void);
void warn_dumpable(void);
const char *gnu_basename(const char *path);
int *str_to_int_array(const char *str, size_t *sz);
#endif
50 changes: 50 additions & 0 deletions src/lib/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <dirent.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include "../include/common.h"
#define BUFLEN 4096

Expand Down Expand Up @@ -320,6 +321,55 @@ const char *gnu_basename(const char *path) {
return last_slash+1;
}

// takes string with comma separated int values, returns int array
int *str_to_int_array(const char *str, size_t *sz) {
assert(str && sz);

size_t curr_sz = 0;
size_t arr_sz = 16;
int *rv = malloc(arr_sz * sizeof(int));
if (!rv)
errExit("malloc");

char *dup = strdup(str);
if (!dup)
errExit("strdup");
char *tok = strtok(dup, ",");
if (!tok) {
free(dup);
free(rv);
goto errout;
}

while (tok) {
char *end;
long val = strtol(tok, &end, 10);
if (end == tok || *end != '\0' || val < INT_MIN || val > INT_MAX) {
free(dup);
free(rv);
goto errout;
}

if (curr_sz == arr_sz) {
arr_sz *= 2;
rv = realloc(rv, arr_sz * sizeof(int));
if (!rv)
errExit("realloc");
}
rv[curr_sz++] = val;

tok = strtok(NULL, ",");
}
free(dup);

*sz = curr_sz;
return rv;

errout:
*sz = 0;
return NULL;
}

//**************************
// time trace based on getticks function
//**************************
Expand Down
5 changes: 5 additions & 0 deletions src/man/firejail-profile.txt
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,11 @@ env CFLAGS="-W -Wall -Werror"
.TP
\fBipc-namespace
Enable IPC namespace.

.TP
\fBkeep-fd
Inherit open file descriptors to sandbox.

.TP
\fBname sandboxname
Set sandbox name. Example:
Expand Down
20 changes: 20 additions & 0 deletions src/man/firejail.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,26 @@ Example:
.br
$ firejail --keep-dev-shm --private-dev

.TP
\fB\-\-keep-fd=all
Inherit 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.
.br

.br
Example:
.br
$ firejail --keep-fd=all

.TP
\fB\-\-keep-fd=file_descriptor
Don'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.
.br

.br
Example:
.br
$ firejail --keep-fd=3,4,5

.TP
\fB\-\-keep-var-tmp
/var/tmp directory is untouched.
Expand Down
1 change: 1 addition & 0 deletions src/zsh_completion/_firejail.in
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ _firejail_args=(
'--join-or-start=-[join the sandbox or start a new one name|pid]: :_all_firejails'
'--keep-config-pulse[disable automatic ~/.config/pulse init]'
'--keep-dev-shm[/dev/shm directory is untouched (even with --private-dev)]'
'--keep-fd[inherit open file descriptors to sandbox]'
'--keep-var-tmp[/var/tmp directory is untouched]'
'--machine-id[spoof /etc/machine-id with a random id]'
'--memory-deny-write-execute[seccomp filter to block attempts to create memory mappings that are both writable and executable]'
Expand Down

0 comments on commit c764520

Please sign in to comment.