Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

keep-fd option (#4845) #4856

Merged
merged 1 commit into from
Jan 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
keep-fd option (#4845)
  • Loading branch information
smitsohu committed Jan 14, 2022
commit c764520b5aa343c00c3a73633511df039645973c
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