From 61b15442898eeb1db2d23b6b2eb72a705ceb368a Mon Sep 17 00:00:00 2001 From: Азалия Смарагдова Date: Mon, 15 Aug 2022 12:19:11 +0500 Subject: Landlock support has been added. --- config.mk.in | 3 +- configure | 16 ++++ configure.ac | 10 ++- contrib/vim/syntax/firejail.vim | 2 +- src/bash_completion/firejail.bash_completion.in | 16 ++++ src/firejail/firejail.h | 3 + src/firejail/main.c | 33 ++++++++ src/firejail/profile.c | 35 ++++++++ src/firejail/sandbox.c | 13 +++ src/firejail/usage.c | 4 + src/include/tinyLL.h | 23 +++++ src/lib/libtinyll.c | 108 ++++++++++++++++++++++++ src/man/firejail-profile.txt | 21 +++++ src/man/firejail.txt | 28 ++++++ src/zsh_completion/_firejail.in | 4 + 15 files changed, 316 insertions(+), 3 deletions(-) create mode 100644 src/include/tinyLL.h create mode 100644 src/lib/libtinyll.c diff --git a/config.mk.in b/config.mk.in index 9973b7eaa..150ac8e15 100644 --- a/config.mk.in +++ b/config.mk.in @@ -41,6 +41,7 @@ HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ HAVE_IDS=@HAVE_IDS@ HAVE_GCOV=@HAVE_GCOV@ HAVE_SELINUX=@HAVE_SELINUX@ +HAVE_LANDLOCK=@HAVE_LANDLOCK@ HAVE_SUID=@HAVE_SUID@ HAVE_DBUSPROXY=@HAVE_DBUSPROXY@ HAVE_USERTMPFS=@HAVE_USERTMPFS@ @@ -49,7 +50,7 @@ HAVE_LTS=@HAVE_LTS@ HAVE_FORCE_NONEWPRIVS=@HAVE_FORCE_NONEWPRIVS@ HAVE_ONLY_SYSCFG_PROFILES=@HAVE_ONLY_SYSCFG_PROFILES@ -MANFLAGS = $(HAVE_LTS) $(HAVE_OUTPUT) $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_IDS) $(HAVE_OVERLAYFS) $(HAVE_USERTMPFS) $(HAVE_DBUSPROXY) $(HAVE_FIRETUNNEL) $(HAVE_GLOBALCFG) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_FILE_TRANSFER) $(HAVE_SELINUX) $(HAVE_SUID) $(HAVE_FORCE_NONEWPRIVS) $(HAVE_ONLY_SYSCFG_PROFILES) +MANFLAGS = $(HAVE_LTS) $(HAVE_OUTPUT) $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_IDS) $(HAVE_OVERLAYFS) $(HAVE_USERTMPFS) $(HAVE_DBUSPROXY) $(HAVE_FIRETUNNEL) $(HAVE_GLOBALCFG) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_FILE_TRANSFER) $(HAVE_SELINUX) $(HAVE_SUID) $(HAVE_LANDLOCK) $(HAVE_FORCE_NONEWPRIVS) $(HAVE_ONLY_SYSCFG_PROFILES) CC=@CC@ CFLAGS=@CFLAGS@ diff --git a/configure b/configure index f3bd77169..7a40e47b4 100755 --- a/configure +++ b/configure @@ -652,6 +652,7 @@ HAVE_DBUSPROXY EXTRA_LDFLAGS EXTRA_CFLAGS HAVE_SELINUX +HAVE_LANDLOCK AA_LIBS AA_CFLAGS PKG_CONFIG_LIBDIR @@ -713,6 +714,7 @@ enable_sanitizer enable_ids enable_apparmor enable_selinux +enable_landlock enable_dbusproxy enable_output enable_usertmpfs @@ -1374,6 +1376,7 @@ Optional Features: --enable-ids enable ids --enable-apparmor enable apparmor --enable-selinux SELinux labeling support + --enable-landlock Landlock self-restriction support --disable-dbusproxy disable dbus proxy --disable-output disable --output logging --disable-usertmpfs disable tmpfs as regular user @@ -3342,7 +3345,19 @@ if test "x$enable_selinux" = "xyes"; then : fi +HAVE_LANDLOCK="" +# Check whether --enable-landlock was given. +if test "${enable_landlock+set}" = set; then : + enableval=$enable_landlock; +fi + +if test "x$enable_landlock" = "xyes"; then : + + HAVE_LANDLOCK="-DHAVE_LANDLOCK" + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -ltinyll" + +fi @@ -5277,6 +5292,7 @@ Features: overlayfs support: $HAVE_OVERLAYFS private home support: $HAVE_PRIVATE_HOME SELinux labeling support: $HAVE_SELINUX + Landlock self-restriction support: $HAVE_LANDLOCK user namespace: $HAVE_USERNS X11 sandboxing support: $HAVE_X11 diff --git a/configure.ac b/configure.ac index 8a488ff43..580ca69f1 100644 --- a/configure.ac +++ b/configure.ac @@ -81,10 +81,18 @@ AS_IF([test "x$enable_selinux" = "xyes"], [ EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lselinux" ]) +HAVE_LANDLOCK="" +AC_SUBST([HAVE_LANDLOCK]) +AC_ARG_ENABLE([landlock]) + [AS_HELP_STRING([--enable-landlock], [Landlock self-restriction support])] +AS_IF([test "x$enable_landlock" = "xyes"], [ + HAVE_LANDLOCK="-DHAVE_LANDLOCK" + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -ltinyll" +]) + AC_SUBST([EXTRA_CFLAGS]) AC_SUBST([EXTRA_LDFLAGS]) - HAVE_DBUSPROXY="" AC_SUBST([HAVE_DBUSPROXY]) AC_ARG_ENABLE([dbusproxy], diff --git a/contrib/vim/syntax/firejail.vim b/contrib/vim/syntax/firejail.vim index 0c8ebdbd8..d3631b5df 100644 --- a/contrib/vim/syntax/firejail.vim +++ b/contrib/vim/syntax/firejail.vim @@ -52,7 +52,7 @@ syn match fjVar /\v\$\{(CFG|DESKTOP|DOCUMENTS|DOWNLOADS|HOME|MUSIC|PATH|PICTURES " Commands grabbed from: src/firejail/profile.c " 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|restrict-namespaces|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(apparmor|bind|blacklist|blacklist-nolog|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 +syn match fjCommand /\v(apparmor|bind|blacklist|blacklist-nolog|cpu|defaultgw|dns|hostname|hosts-file|ip6|iprange|join-or-start|landlock-read|landlock-write|landlock-restricted-write|landlock-execute|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 /ignore / nextgroup=fjCommand,fjCommandNoCond skipwhite contained diff --git a/src/bash_completion/firejail.bash_completion.in b/src/bash_completion/firejail.bash_completion.in index 8e047ce90..83d11d766 100644 --- a/src/bash_completion/firejail.bash_completion.in +++ b/src/bash_completion/firejail.bash_completion.in @@ -42,6 +42,22 @@ _firejail() _filedir -d return 0 ;; + --landlock-read) + _filedir + return 0 + ;; + --landlock-write) + _filedir + return 0 + ;; + --landlock-restricted-write) + _filedir + return 0 + ;; + --landlock-execute) + _filedir + return 0 + ;; --tmpfs) _filedir return 0 diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 0a4dffb75..6a679f849 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -23,6 +23,7 @@ #include "../include/euid_common.h" #include "../include/rundefs.h" #include // Note: Plain limits.h may break ARG_MAX (see #4583) +#include #include #include @@ -286,6 +287,8 @@ extern int arg_seccomp32; // enable default seccomp filter for 32 bit arch extern int arg_seccomp_postexec; // need postexec ld.preload library? extern int arg_seccomp_block_secondary; // block any secondary architectures +extern int arg_landlock; // Landlock ruleset file descriptor + extern int arg_caps_default_filter; // enable default capabilities filter extern int arg_caps_drop; // drop list extern int arg_caps_drop_all; // drop all capabilities diff --git a/src/firejail/main.c b/src/firejail/main.c index 29c25dfc5..cff6eba5f 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -23,6 +23,9 @@ #include "../include/gcov_wrapper.h" #include "../include/syscall.h" #include "../include/seccomp.h" +#ifdef HAVE_LANDLOCK +#include "../include/tinyLL.h" +#endif #define _GNU_SOURCE #include #include @@ -81,6 +84,10 @@ int arg_seccomp_postexec = 0; // need postexec ld.preload library? int arg_seccomp_block_secondary = 0; // block any secondary architectures int arg_seccomp_error_action = 0; +#ifdef HAVE_LANDLOCK +int arg_landlock = -1; // Landlock ruleset file descriptor (-1 if it doesn't exist) +#endif + int arg_caps_default_filter = 0; // enable default capabilities filter int arg_caps_drop = 0; // drop list int arg_caps_drop_all = 0; // drop all capabilities @@ -1401,6 +1408,32 @@ int main(int argc, char **argv, char **envp) { else exit_err_feature("seccomp"); } +#ifdef HAVE_LANDLOCK + else if (strncmp(argv[i], "--landlock-read=", 16) == 0) { + if (arg_landlock == -1) arg_landlock = create_full_ruleset(); + if (add_read_access_rule_by_path(arg_landlock, argv[i]+16)) { + fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); + } + } + else if (strncmp(argv[i], "--landlock-write=", 17) == 0) { + if (arg_landlock == -1) arg_landlock = create_full_ruleset(); + if (add_write_access_rule_by_path(arg_landlock, argv[i]+17,0)) { + fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); + } + } + else if (strncmp(argv[i], "--landlock-restricted-write=", 28) == 0) { + if (arg_landlock == -1) arg_landlock = create_full_ruleset(); + if (add_write_access_rule_by_path(arg_landlock, argv[i]+28,1)) { + fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); + } + } + else if (strncmp(argv[i], "--landlock-execute=", 19) == 0) { + if (arg_landlock == -1) arg_landlock = create_full_ruleset(); + if (add_execute_rule_by_path(arg_landlock, argv[i]+19)) { + fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); + } + } +#endif else if (strcmp(argv[i], "--memory-deny-write-execute") == 0) { if (checkcfg(CFG_SECCOMP)) arg_memory_deny_write_execute = 1; diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 82f8a393b..9d154adee 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c @@ -21,6 +21,9 @@ #include "../include/gcov_wrapper.h" #include "../include/seccomp.h" #include "../include/syscall.h" +#ifdef HAVE_LANDLOCK +#include "../include/tinyLL.h" +#endif #include #include @@ -1045,6 +1048,38 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { return 0; } +#ifdef HAVE_LANDLOCK + // Landlock ruleset paths + if (strncmp(ptr, "landlock-read ", 14) == 0) { + if (arg_landlock == -1) arg_landlock = create_full_ruleset(); + if (add_read_access_rule_by_path(arg_landlock, ptr+14)) { + fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); + } + return 0; + } + else if (strncmp(ptr, "landlock-write ", 15) == 0) { + if (arg_landlock == -1) arg_landlock = create_full_ruleset(); + if (add_write_access_rule_by_path(arg_landlock, ptr+15,0)) { + fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); + } + return 0; + } + else if (strncmp(ptr, "landlock-restricted-write ", 26) == 0) { + if (arg_landlock == -1) arg_landlock = create_full_ruleset(); + if (add_write_access_rule_by_path(arg_landlock, ptr+26,1)) { + fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); + } + return 0; + } + else if (strncmp(ptr, "landlock-execute ", 17) == 0) { + if (arg_landlock == -1) arg_landlock = create_full_ruleset(); + if (add_execute_rule_by_path(arg_landlock, ptr+17)) { + fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); + } + return 0; + } +#endif + // memory deny write&execute if (strcmp(ptr, "memory-deny-write-execute") == 0) { if (checkcfg(CFG_SECCOMP)) diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 9299268a3..73f2aa211 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c @@ -21,6 +21,9 @@ #include "firejail.h" #include "../include/gcov_wrapper.h" #include "../include/seccomp.h" +#ifdef HAVE_LANDLOCK +#include "../include/tinyLL.h" +#endif #include #include #include @@ -488,6 +491,16 @@ void start_application(int no_sandbox, int fd, char *set_sandbox_status) { #ifdef HAVE_APPARMOR set_apparmor(); #endif +#ifdef HAVE_LANDLOCK + // set Landlock + if (arg_landlock >= 0) { + if (landlock_restrict_self(arg_landlock,0)) { + fprintf(stderr,"An error has occured while enabling Landlock self-restriction. Exiting...\n"); + exit(1); // it isn't safe to continue if Landlock self-restriction was enabled and the "landlock_restrict_self" syscall has failed + } + } +#endif + close_file_descriptors(); // set nice and rlimits diff --git a/src/firejail/usage.c b/src/firejail/usage.c index e11081eed..485d08ab0 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c @@ -122,6 +122,10 @@ static char *usage_str = " --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" + " --landlock-read=path - add a read access rule for the path to the Landlock ruleset.\n" + " --landlock-write=path - add a write access rule for the path to the Landlock ruleset.\n" + " --landlock-restricted-write=path - add a write access rule that doesn't include creating FIFO pipes, Unix domain sockets and block devices for the path to the Landlock ruleset.\n" + " --landlock-execute=path - add an execution-permitting rule for the path to the Landlock ruleset.\n" " --list - list all sandboxes.\n" #ifdef HAVE_FILE_TRANSFER " --ls=name|pid dir_or_filename - list files in sandbox container.\n" diff --git a/src/include/tinyLL.h b/src/include/tinyLL.h new file mode 100644 index 000000000..f5cd20876 --- /dev/null +++ b/src/include/tinyLL.h @@ -0,0 +1,23 @@ +extern int landlock_create_ruleset(struct landlock_ruleset_attr *rsattr,size_t size,__u32 flags); + +extern int landlock_add_rule(int fd,enum landlock_rule_type t,void *attr,__u32 flags); + +extern int landlock_restrict_self(int fd,__u32 flags); + +extern int create_full_ruleset(); + +extern int add_read_access_rule(int rset_fd,int allowed_fd); + +extern int add_read_access_rule_by_path(int rset_fd,char *allowed_path); + +extern int add_write_access_rule(int rset_fd,int allowed_fd,int restricted); + +extern int add_write_access_rule_by_path(int rset_fd,char *allowed_path,int restricted); + +extern int add_execute_rule(int rset_fd,int allowed_fd); + +extern int add_execute_rule_by_path(int rset_fd,char *allowed_path); + +extern int check_nnp(); + +extern int enable_nnp(); diff --git a/src/lib/libtinyll.c b/src/lib/libtinyll.c new file mode 100644 index 000000000..9db6f75d7 --- /dev/null +++ b/src/lib/libtinyll.c @@ -0,0 +1,108 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int landlock_create_ruleset(struct landlock_ruleset_attr *rsattr,size_t size,__u32 flags) { + return syscall(__NR_landlock_create_ruleset,rsattr,size,flags); +} + +int landlock_add_rule(int fd,enum landlock_rule_type t,void *attr,__u32 flags) { + return syscall(__NR_landlock_add_rule,fd,t,attr,flags); +} + +int landlock_restrict_self(int fd,__u32 flags) { + int result = syscall(__NR_landlock_restrict_self,fd,flags); + if (result!=0) return result; + else { + close(fd); + return 0; + } +} + +int create_full_ruleset() { + struct landlock_ruleset_attr attr; + attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_REMOVE_DIR | LANDLOCK_ACCESS_FS_MAKE_CHAR | LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_MAKE_SOCK | LANDLOCK_ACCESS_FS_MAKE_FIFO | LANDLOCK_ACCESS_FS_MAKE_BLOCK | LANDLOCK_ACCESS_FS_MAKE_SYM | LANDLOCK_ACCESS_FS_EXECUTE; + return landlock_create_ruleset(&attr,sizeof(attr),0); +} + +int add_read_access_rule(int rset_fd,int allowed_fd) { + int result; + struct landlock_path_beneath_attr target; + target.parent_fd = allowed_fd; + target.allowed_access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR; + result = landlock_add_rule(rset_fd,LANDLOCK_RULE_PATH_BENEATH,&target,0); + return result; +} + +int add_read_access_rule_by_path(int rset_fd,char *allowed_path) { + int result; + int allowed_fd = open(allowed_path,O_PATH | O_CLOEXEC); + struct landlock_path_beneath_attr target; + target.parent_fd = allowed_fd; + target.allowed_access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR; + result = landlock_add_rule(rset_fd,LANDLOCK_RULE_PATH_BENEATH,&target,0); + close(allowed_fd); + return result; +} + +int add_write_access_rule(int rset_fd,int allowed_fd,int restricted) { + int result; + struct landlock_path_beneath_attr target; + target.parent_fd = allowed_fd; + if (restricted==0) target.allowed_access = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_REMOVE_DIR | LANDLOCK_ACCESS_FS_MAKE_CHAR | LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_MAKE_SOCK | LANDLOCK_ACCESS_FS_MAKE_FIFO | LANDLOCK_ACCESS_FS_MAKE_BLOCK | LANDLOCK_ACCESS_FS_MAKE_SYM; + else if (restricted==1) target.allowed_access = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_REMOVE_DIR | LANDLOCK_ACCESS_FS_MAKE_CHAR | LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_MAKE_SYM; + result = landlock_add_rule(rset_fd,LANDLOCK_RULE_PATH_BENEATH,&target,0); + return result; +} + +int add_write_access_rule_by_path(int rset_fd,char *allowed_path,int restricted) { + int result; + int allowed_fd = open(allowed_path,O_PATH | O_CLOEXEC); + struct landlock_path_beneath_attr target; + target.parent_fd = allowed_fd; + if (restricted==0) target.allowed_access = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_REMOVE_DIR | LANDLOCK_ACCESS_FS_MAKE_CHAR | LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_MAKE_SOCK | LANDLOCK_ACCESS_FS_MAKE_FIFO | LANDLOCK_ACCESS_FS_MAKE_BLOCK | LANDLOCK_ACCESS_FS_MAKE_SYM; + else if (restricted==1) target.allowed_access = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_REMOVE_DIR | LANDLOCK_ACCESS_FS_MAKE_CHAR | LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_MAKE_SYM; + else { + close(allowed_fd); + return -1; + } + result = landlock_add_rule(rset_fd,LANDLOCK_RULE_PATH_BENEATH,&target,0); + close(allowed_fd); + return result; +} + +int add_execute_rule(int rset_fd,int allowed_fd) { + int result; + struct landlock_path_beneath_attr target; + target.parent_fd = allowed_fd; + target.allowed_access = LANDLOCK_ACCESS_FS_EXECUTE; + result = landlock_add_rule(rset_fd,LANDLOCK_RULE_PATH_BENEATH,&target,0); + return result; +} + +int add_execute_rule_by_path(int rset_fd,char *allowed_path) { + int result; + int allowed_fd = open(allowed_path,O_PATH | O_CLOEXEC); + struct landlock_path_beneath_attr target; + target.parent_fd = allowed_fd; + target.allowed_access = LANDLOCK_ACCESS_FS_EXECUTE; + result = landlock_add_rule(rset_fd,LANDLOCK_RULE_PATH_BENEATH,&target,0); + close(allowed_fd); + return result; +} + +int check_nnp() { + return prctl(PR_GET_NO_NEW_PRIVS,0,0,0,0); +} + +int enable_nnp() { + return prctl(PR_SET_NO_NEW_PRIVS,1,0,0,0); +} diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 138aae8af..6e75aceed 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt @@ -497,6 +497,27 @@ Blacklist all Linux capabilities. .TP \fBcaps.keep capability,capability,capability Whitelist given Linux capabilities. +#ifdef HAVE_LANDLOCK +.TP +\fBlandlock-read path +Create a Landlock ruleset (if it doesn't already exist) and add a read access rule for path. Note: if a process doesn't have CAP_SYS_ADMIN and the "No New Privileges" restriction is not enabled, the Landlock self-restriction will fail and Firejail will exit with an error. +.br + +.TP +\fBlandlock-write path +Create a Landlock ruleset (if it doesn't already exist) and add a write access rule for path. Note: if a process doesn't have CAP_SYS_ADMIN and the "No New Privileges" restriction is not enabled, the Landlock self-restriction will fail and Firejail will exit with an error. +.br + +.TP +\fBlandlock-restricted-write path +Create a Landlock ruleset (if it doesn't already exist) and add a write access rule for path. This type of write access doesn't include the permission to create Unix domain sockets, FIFO pipes and block devices. Note: if a process doesn't have CAP_SYS_ADMIN and the "No New Privileges" restriction is not enabled, the Landlock self-restriction will fail and Firejail will exit with an error. +.br + +.TP +\fBlandlock-execute path +Create a Landlock ruleset (if it doesn't already exist) and add an execution permission rule for path. Note: if a process doesn't have CAP_SYS_ADMIN and the "No New Privileges" restriction is not enabled, the Landlock self-restriction will fail and Firejail will exit with an error. +.br +#endif .TP \fBmemory-deny-write-execute Install a seccomp filter to block attempts to create memory mappings diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 2d8adb0b7..7082fe0ab 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt @@ -1144,6 +1144,33 @@ Example: .br $ firejail --keep-var-tmp +#ifdef HAVE_LANDLOCK +.TP +\fB\-\-landlock-read=path +Create a Landlock ruleset (if it doesn't already exist) and add a read access rule for path. Note: if a process doesn't have CAP_SYS_ADMIN and the "No New Privileges" restriction is not enabled, the Landlock self-restriction will fail and Firejail will exit with an error. +.br + +.TP +\fB\-\-landlock-write=path +Create a Landlock ruleset (if it doesn't already exist) and add a write access rule for path. Note: if a process doesn't have CAP_SYS_ADMIN and the "No New Privileges" restriction is not enabled, the Landlock self-restriction will fail and Firejail will exit with an error. +.br + +.TP +\fB\-\-landlock-restricted-write=path +Create a Landlock ruleset (if it doesn't already exist) and add a write access rule for path. This type of write access doesn't include the permission to create Unix domain sockets, FIFO pipes and block devices. Note: if a process doesn't have CAP_SYS_ADMIN and the "No New Privileges" restriction is not enabled, the Landlock self-restriction will fail and Firejail will exit with an error. +.br + +.TP +\fB\-\-landlock-execute=path +Create a Landlock ruleset (if it doesn't already exist) and add an execution permission rule for path. Note: if a process doesn't have CAP_SYS_ADMIN and the "No New Privileges" restriction is not enabled, the Landlock self-restriction will fail and Firejail will exit with an error. +.br + +.br +Example: +.br +$ firejail \-\-landlock-read=/ \-\-landlock-restricted-write=/home \-\-landlock-execute=/usr +#endif + .TP \fB\-\-list List all sandboxes, see \fBMONITORING\fR section for more details. @@ -1261,6 +1288,7 @@ $ firejail --list .br 1312:netblue:browser-1312:firejail --name=browser --private firefox --no-remote .br + #ifdef HAVE_NETWORK .TP \fB\-\-net=bridge_interface diff --git a/src/zsh_completion/_firejail.in b/src/zsh_completion/_firejail.in index 2b67c2a00..661929db9 100644 --- a/src/zsh_completion/_firejail.in +++ b/src/zsh_completion/_firejail.in @@ -105,6 +105,10 @@ _firejail_args=( '--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]' + '--landlock-read=-[Landlock read access rule]: :_files' + '--landlock-write=-[Landlock write access rule]: :_files' + '--landlock-restricted-write=-[Landlock write access rule that doesn't include creation of FIFO pipes, sockets and block devices]: :_files' + '--landlock-execute=-[Landlock execution-permitting rule]: :_files' '--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]' '*--mkdir=-[create a directory]:' -- cgit v1.2.3-54-g00ecf