diff --git a/contrib/vim/syntax/firejail.vim b/contrib/vim/syntax/firejail.vim index 714ed8e6ebf..1049fb909e7 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|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 /\v(allow-debuggers|allusers|apparmor|caps|deterministic-exit-code|deterministic-shutdown|disable-mnt|ipc-namespace|keep-config-pulse|keep-dev-shm|keep-fd|keep-xattrs|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 diff --git a/src/firejail/dhcp.c b/src/firejail/dhcp.c index fb66d74ff49..d7658029891 100644 --- a/src/firejail/dhcp.c +++ b/src/firejail/dhcp.c @@ -146,7 +146,7 @@ void dhcp_store_exec(void) { } } - sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", dhclient_path, RUN_MNT_DIR); + sbox_run(SBOX_ROOT| SBOX_SECCOMP, 6, PATH_FCOPY, "--follow-link", "--keep-xattrs", cfg.keep_xattrs, dhclient_path, RUN_MNT_DIR); } void dhcp_start(void) { diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 316518534ea..58e39858329 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -162,6 +162,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 *keep_xattrs; // keep xattrs on copied files char *chrootdir; // chroot directory char *home_private; // private home directory char *home_private_keep; // keep list for private home directory diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c index 2b0b3003e8b..323004d4fbe 100644 --- a/src/firejail/fs_bin.c +++ b/src/firejail/fs_bin.c @@ -187,7 +187,7 @@ static void duplicate(char *fname) { if (valid_full_path_file(actual_path)) { // solving problems such as /bin/sh -> /bin/dash // copy the real file pointed by symlink - sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, actual_path, RUN_BIN_DIR); + sbox_run(SBOX_ROOT| SBOX_SECCOMP, 5, PATH_FCOPY, "--keep-xattrs", cfg.keep_xattrs, actual_path, RUN_BIN_DIR); prog_cnt++; char *f = strrchr(actual_path, '/'); if (f && *(++f) !='\0') @@ -198,7 +198,7 @@ static void duplicate(char *fname) { } // copy a file or a symlink - sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, full_path, RUN_BIN_DIR); + sbox_run(SBOX_ROOT| SBOX_SECCOMP, 5, PATH_FCOPY, "--keep-xattrs", cfg.keep_xattrs, full_path, RUN_BIN_DIR); prog_cnt++; free(full_path); report_duplication(fname); diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c index deaee31bbaa..3caa6ec0cc0 100644 --- a/src/firejail/fs_etc.c +++ b/src/firejail/fs_etc.c @@ -170,9 +170,9 @@ static void duplicate(const char *fname, const char *private_dir, const char *pr // this will solve problems such as NixOS #4887 // don't follow links to dynamic directories such as /proc if (strcmp(src, "/etc/mtab") == 0) - sbox_run(SBOX_ROOT | SBOX_SECCOMP, 3, PATH_FCOPY, src, dst); + sbox_run(SBOX_ROOT | SBOX_SECCOMP, 5, PATH_FCOPY, "--keep-xattrs", cfg.keep_xattrs, src, dst); else - sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", src, dst); + sbox_run(SBOX_ROOT | SBOX_SECCOMP, 6, PATH_FCOPY, "--follow-link", "--keep-xattrs", cfg.keep_xattrs, src, dst); free(dst); fs_logger2("clone", src); diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 061461590e9..d046e48f8ae 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c @@ -569,11 +569,11 @@ static void duplicate(char *name) { if (asprintf(&path, "%s/%s", RUN_HOME_DIR, ptr) == -1) errExit("asprintf"); create_empty_dir_as_user(path, 0755); - sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, path); + sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 5, PATH_FCOPY, "--keep-xattrs", cfg.keep_xattrs, fname, path); free(path); } else - sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, RUN_HOME_DIR); + sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 5, PATH_FCOPY, "--keep-xattrs", cfg.keep_xattrs, fname, RUN_HOME_DIR); fs_logger2("clone", fname); fs_logger_print(); // save the current log diff --git a/src/firejail/main.c b/src/firejail/main.c index fd96f8bb58d..80be3f10560 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -1885,6 +1885,10 @@ int main(int argc, char **argv, char **envp) { profile_list_augment(&cfg.keep_fd, add); } } + else if (strncmp(argv[i], "--keep-xattrs=", 14) == 0) { + const char *xattr = argv[i] + 14; + profile_list_augment(&cfg.keep_xattrs, xattr); + } #ifdef HAVE_CHROOT else if (strncmp(argv[i], "--chroot=", 9) == 0) { if (checkcfg(CFG_CHROOT)) { @@ -2972,6 +2976,10 @@ int main(int argc, char **argv, char **envp) { } EUID_ASSERT(); + // make sure that the xattr list is not null + if (!cfg.keep_xattrs) + cfg.keep_xattrs = ""; + // block X11 sockets if (arg_x11_block) x11_block(); diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 5bc77263a31..56cf8962b02 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c @@ -303,6 +303,11 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { } return 0; } + if (strncmp(ptr, "keep-xattrs ", 12) == 0) { + const char *xattr = ptr + 12; + profile_list_augment(&cfg.keep_xattrs, xattr); + return 0; + } if (strncmp(ptr, "xephyr-screen ", 14) == 0) { #ifdef HAVE_X11 if (checkcfg(CFG_X11)) { diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 2dd913b5e3d..71d5a56a7dd 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c @@ -120,6 +120,7 @@ static char *usage_str = " --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-xattrs=name,name,name - copy the specified extended attributes to the sandbox.\n" " --keep-var-tmp - /var/tmp directory is untouched.\n" " --list - list all sandboxes.\n" #ifdef HAVE_FILE_TRANSFER diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 0fe434faccc..64a25bede9f 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt @@ -745,6 +745,10 @@ Enable IPC namespace. \fBkeep-fd Inherit open file descriptors to sandbox. +.TP +\fBkeep-xattrs name,name,name +Copy the specified extended attributes to the sandbox. + .TP \fBname sandboxname Set sandbox name. Example: diff --git a/src/man/firejail.txt b/src/man/firejail.txt index cf80ab25c1a..6d9f21149d8 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt @@ -1123,6 +1123,16 @@ Example: .br $ firejail --keep-fd=3,4,5 +.TP +\fB\-\-keep-xattrs=name,name,name +Copy the specified extended attributes. By default, none of the xattrs are copied for files in private-bin, private-etc and private-home. Attributes are always preserved for bind-mounted files. See xattr(7) for details. +.br + +.br +Example: +.br +$ firejail --keep-xattrs=security.ima,security.SMACK64 + .TP \fB\-\-keep-var-tmp /var/tmp directory is untouched. diff --git a/src/zsh_completion/_firejail.in b/src/zsh_completion/_firejail.in index f7cd3cdfffa..73c50252605 100644 --- a/src/zsh_completion/_firejail.in +++ b/src/zsh_completion/_firejail.in @@ -105,6 +105,7 @@ _firejail_args=( '--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-xattrs=-[copy the specified extended attributes to the 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]'