aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/vim/syntax/firejail.vim2
-rw-r--r--src/bash_completion/firejail.bash_completion.in8
-rw-r--r--src/firejail/firejail.h7
-rw-r--r--src/firejail/landlock.c23
-rw-r--r--src/firejail/main.c63
-rw-r--r--src/firejail/profile.c64
-rw-r--r--src/firejail/sandbox.c35
-rw-r--r--src/firejail/usage.c10
-rw-r--r--src/firejail/util.c4
-rw-r--r--src/man/firejail-profile.txt24
-rw-r--r--src/man/firejail.txt53
-rw-r--r--src/zsh_completion/_firejail.in10
12 files changed, 242 insertions, 61 deletions
diff --git a/contrib/vim/syntax/firejail.vim b/contrib/vim/syntax/firejail.vim
index d3631b5df..7c1c33421 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
52 52
53" Commands grabbed from: src/firejail/profile.c 53" Commands grabbed from: src/firejail/profile.c
54" 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) 54" 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)
55syn 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 55syn match fjCommand /\v(apparmor|bind|blacklist|blacklist-nolog|cpu|defaultgw|dns|hostname|hosts-file|ip6|iprange|join-or-start|landlock|landlock.proc|landlock.read|landlock.write|landlock.special|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
56" 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 56" 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
57syn 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 57syn 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
58syn match fjCommand /ignore / nextgroup=fjCommand,fjCommandNoCond skipwhite contained 58syn 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 83d11d766..4829f1fde 100644
--- a/src/bash_completion/firejail.bash_completion.in
+++ b/src/bash_completion/firejail.bash_completion.in
@@ -42,19 +42,19 @@ _firejail()
42 _filedir -d 42 _filedir -d
43 return 0 43 return 0
44 ;; 44 ;;
45 --landlock-read) 45 --landlock.read)
46 _filedir 46 _filedir
47 return 0 47 return 0
48 ;; 48 ;;
49 --landlock-write) 49 --landlock.write)
50 _filedir 50 _filedir
51 return 0 51 return 0
52 ;; 52 ;;
53 --landlock-restricted-write) 53 --landlock.special)
54 _filedir 54 _filedir
55 return 0 55 return 0
56 ;; 56 ;;
57 --landlock-execute) 57 --landlock.execute)
58 _filedir 58 _filedir
59 return 0 59 return 0
60 ;; 60 ;;
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 35e2dbf50..9c2b53c18 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -44,7 +44,9 @@ extern int create_full_ruleset();
44 44
45extern int add_read_access_rule_by_path(int rset_fd,char *allowed_path); 45extern int add_read_access_rule_by_path(int rset_fd,char *allowed_path);
46 46
47extern int add_write_access_rule_by_path(int rset_fd,char *allowed_path,int restricted); 47extern int add_write_access_rule_by_path(int rset_fd,char *allowed_path);
48
49extern int add_create_special_rule_by_path(int rset_fd,char *allowed_path);
48 50
49extern int add_execute_rule_by_path(int rset_fd,char *allowed_path); 51extern int add_execute_rule_by_path(int rset_fd,char *allowed_path);
50 52
@@ -305,7 +307,10 @@ extern int arg_seccomp32; // enable default seccomp filter for 32 bit arch
305extern int arg_seccomp_postexec; // need postexec ld.preload library? 307extern int arg_seccomp_postexec; // need postexec ld.preload library?
306extern int arg_seccomp_block_secondary; // block any secondary architectures 308extern int arg_seccomp_block_secondary; // block any secondary architectures
307 309
310#ifdef HAVE_LANDLOCK
308extern int arg_landlock; // Landlock ruleset file descriptor 311extern int arg_landlock; // Landlock ruleset file descriptor
312extern int arg_landlock_proc; // Landlock rule for accessing /proc (0 for no access, 1 for read-only and 2 for read-write)
313#endif
309 314
310extern int arg_caps_default_filter; // enable default capabilities filter 315extern int arg_caps_default_filter; // enable default capabilities filter
311extern int arg_caps_drop; // drop list 316extern int arg_caps_drop; // drop list
diff --git a/src/firejail/landlock.c b/src/firejail/landlock.c
index 5d6b0260e..67e2b2cfc 100644
--- a/src/firejail/landlock.c
+++ b/src/firejail/landlock.c
@@ -6,6 +6,8 @@
6#include <fcntl.h> 6#include <fcntl.h>
7#include <sys/syscall.h> 7#include <sys/syscall.h>
8#include <sys/types.h> 8#include <sys/types.h>
9#include <sys/prctl.h>
10#include <linux/prctl.h>
9#include <linux/landlock.h> 11#include <linux/landlock.h>
10 12
11int landlock_create_ruleset(struct landlock_ruleset_attr *rsattr,size_t size,__u32 flags) { 13int landlock_create_ruleset(struct landlock_ruleset_attr *rsattr,size_t size,__u32 flags) {
@@ -17,6 +19,7 @@ int landlock_add_rule(int fd,enum landlock_rule_type t,void *attr,__u32 flags) {
17} 19}
18 20
19int landlock_restrict_self(int fd,__u32 flags) { 21int landlock_restrict_self(int fd,__u32 flags) {
22 prctl(PR_SET_NO_NEW_PRIVS,1,0,0,0);
20 int result = syscall(__NR_landlock_restrict_self,fd,flags); 23 int result = syscall(__NR_landlock_restrict_self,fd,flags);
21 if (result!=0) return result; 24 if (result!=0) return result;
22 else { 25 else {
@@ -42,17 +45,23 @@ int add_read_access_rule_by_path(int rset_fd,char *allowed_path) {
42 return result; 45 return result;
43} 46}
44 47
45int add_write_access_rule_by_path(int rset_fd,char *allowed_path,int restricted) { 48int add_write_access_rule_by_path(int rset_fd,char *allowed_path) {
46 int result; 49 int result;
47 int allowed_fd = open(allowed_path,O_PATH | O_CLOEXEC); 50 int allowed_fd = open(allowed_path,O_PATH | O_CLOEXEC);
48 struct landlock_path_beneath_attr target; 51 struct landlock_path_beneath_attr target;
49 target.parent_fd = allowed_fd; 52 target.parent_fd = allowed_fd;
50 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; 53 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;
51 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; 54 result = landlock_add_rule(rset_fd,LANDLOCK_RULE_PATH_BENEATH,&target,0);
52 else { 55 close(allowed_fd);
53 close(allowed_fd); 56 return result;
54 return -1; 57}
55 } 58
59int add_create_special_rule_by_path(int rset_fd,char *allowed_path) {
60 int result;
61 int allowed_fd = open(allowed_path,O_PATH | O_CLOEXEC);
62 struct landlock_path_beneath_attr target;
63 target.parent_fd = allowed_fd;
64 target.allowed_access = LANDLOCK_ACCESS_FS_MAKE_SOCK | LANDLOCK_ACCESS_FS_MAKE_FIFO | LANDLOCK_ACCESS_FS_MAKE_BLOCK;
56 result = landlock_add_rule(rset_fd,LANDLOCK_RULE_PATH_BENEATH,&target,0); 65 result = landlock_add_rule(rset_fd,LANDLOCK_RULE_PATH_BENEATH,&target,0);
57 close(allowed_fd); 66 close(allowed_fd);
58 return result; 67 return result;
diff --git a/src/firejail/main.c b/src/firejail/main.c
index c78d4d2b8..3f0dc960a 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -83,6 +83,7 @@ int arg_seccomp_error_action = 0;
83 83
84#ifdef HAVE_LANDLOCK 84#ifdef HAVE_LANDLOCK
85int arg_landlock = -1; // Landlock ruleset file descriptor (-1 if it doesn't exist) 85int arg_landlock = -1; // Landlock ruleset file descriptor (-1 if it doesn't exist)
86int arg_landlock_proc = 0; // Landlock rule for accessing /proc (0 for no access, 1 for read-only and 2 for read-write)
86#endif 87#endif
87 88
88int arg_caps_default_filter = 0; // enable default capabilities filter 89int arg_caps_default_filter = 0; // enable default capabilities filter
@@ -1406,25 +1407,75 @@ int main(int argc, char **argv, char **envp) {
1406 exit_err_feature("seccomp"); 1407 exit_err_feature("seccomp");
1407 } 1408 }
1408#ifdef HAVE_LANDLOCK 1409#ifdef HAVE_LANDLOCK
1409 else if (strncmp(argv[i], "--landlock-read=", 16) == 0) { 1410 else if (strcmp(argv[i], "--landlock") == 0) {
1411 if (arg_landlock == -1) arg_landlock = create_full_ruleset();
1412 const char *home_dir = env_get("HOME");
1413 int home_fd = open(home_dir,O_PATH | O_CLOEXEC);
1414 struct landlock_path_beneath_attr target;
1415 target.parent_fd = home_fd;
1416 target.allowed_access = 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_SYM;
1417 if (landlock_add_rule(arg_landlock,LANDLOCK_RULE_PATH_BENEATH,&target,0)) {
1418 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1419 }
1420 close(home_fd);
1421 if (add_read_access_rule_by_path(arg_landlock, "/bin/")) {
1422 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1423 }
1424 if (add_execute_rule_by_path(arg_landlock, "/bin/")) {
1425 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1426 }
1427 if (add_read_access_rule_by_path(arg_landlock, "/dev/")) {
1428 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1429 }
1430 if (add_read_access_rule_by_path(arg_landlock, "/etc/")) {
1431 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1432 }
1433 if (add_read_access_rule_by_path(arg_landlock, "/lib/")) {
1434 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1435 }
1436 if (add_execute_rule_by_path(arg_landlock, "/lib/")) {
1437 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1438 }
1439 if (add_read_access_rule_by_path(arg_landlock, "/opt/")) {
1440 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1441 }
1442 if (add_execute_rule_by_path(arg_landlock, "/opt/")) {
1443 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1444 }
1445 if (add_read_access_rule_by_path(arg_landlock, "/usr/")) {
1446 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1447 }
1448 if (add_execute_rule_by_path(arg_landlock, "/usr/")) {
1449 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1450 }
1451 if (add_read_access_rule_by_path(arg_landlock, "/var/")) {
1452 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1453 }
1454 }
1455 else if (strncmp(argv[i], "--landlock.proc=", 16) == 0) {
1456 if (strncmp(argv[i]+16, "no", 2) == 0) arg_landlock_proc = 0;
1457 else if (strncmp(argv[i]+16, "ro", 2) == 0) arg_landlock_proc = 1;
1458 else if (strncmp(argv[i]+16, "rw", 2) == 0) arg_landlock_proc = 2;
1459 }
1460 else if (strncmp(argv[i], "--landlock.read=", 16) == 0) {
1410 if (arg_landlock == -1) arg_landlock = create_full_ruleset(); 1461 if (arg_landlock == -1) arg_landlock = create_full_ruleset();
1411 if (add_read_access_rule_by_path(arg_landlock, argv[i]+16)) { 1462 if (add_read_access_rule_by_path(arg_landlock, argv[i]+16)) {
1412 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); 1463 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1413 } 1464 }
1414 } 1465 }
1415 else if (strncmp(argv[i], "--landlock-write=", 17) == 0) { 1466 else if (strncmp(argv[i], "--landlock.write=", 17) == 0) {
1416 if (arg_landlock == -1) arg_landlock = create_full_ruleset(); 1467 if (arg_landlock == -1) arg_landlock = create_full_ruleset();
1417 if (add_write_access_rule_by_path(arg_landlock, argv[i]+17,0)) { 1468 if (add_write_access_rule_by_path(arg_landlock, argv[i]+17)) {
1418 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); 1469 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1419 } 1470 }
1420 } 1471 }
1421 else if (strncmp(argv[i], "--landlock-restricted-write=", 28) == 0) { 1472 else if (strncmp(argv[i], "--landlock.special=", 17) == 0) {
1422 if (arg_landlock == -1) arg_landlock = create_full_ruleset(); 1473 if (arg_landlock == -1) arg_landlock = create_full_ruleset();
1423 if (add_write_access_rule_by_path(arg_landlock, argv[i]+28,1)) { 1474 if (add_create_special_rule_by_path(arg_landlock, argv[i]+17)) {
1424 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); 1475 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1425 } 1476 }
1426 } 1477 }
1427 else if (strncmp(argv[i], "--landlock-execute=", 19) == 0) { 1478 else if (strncmp(argv[i], "--landlock.execute=", 19) == 0) {
1428 if (arg_landlock == -1) arg_landlock = create_full_ruleset(); 1479 if (arg_landlock == -1) arg_landlock = create_full_ruleset();
1429 if (add_execute_rule_by_path(arg_landlock, argv[i]+19)) { 1480 if (add_execute_rule_by_path(arg_landlock, argv[i]+19)) {
1430 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); 1481 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 64a82767c..2969db85b 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -1047,28 +1047,80 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
1047 1047
1048#ifdef HAVE_LANDLOCK 1048#ifdef HAVE_LANDLOCK
1049 // Landlock ruleset paths 1049 // Landlock ruleset paths
1050 if (strncmp(ptr, "landlock-read ", 14) == 0) { 1050 if (strcmp(ptr, "landlock") == 0) {
1051 if (arg_landlock == -1) arg_landlock = create_full_ruleset();
1052 const char *home_dir = env_get("HOME");
1053 int home_fd = open(home_dir,O_PATH | O_CLOEXEC);
1054 struct landlock_path_beneath_attr target;
1055 target.parent_fd = home_fd;
1056 target.allowed_access = 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_SYM;
1057 if (landlock_add_rule(arg_landlock,LANDLOCK_RULE_PATH_BENEATH,&target,0)) {
1058 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1059 }
1060 close(home_fd);
1061 if (add_read_access_rule_by_path(arg_landlock, "/bin/")) {
1062 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1063 }
1064 if (add_execute_rule_by_path(arg_landlock, "/bin/")) {
1065 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1066 }
1067 if (add_read_access_rule_by_path(arg_landlock, "/dev/")) {
1068 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1069 }
1070 if (add_read_access_rule_by_path(arg_landlock, "/etc/")) {
1071 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1072 }
1073 if (add_read_access_rule_by_path(arg_landlock, "/lib/")) {
1074 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1075 }
1076 if (add_execute_rule_by_path(arg_landlock, "/lib/")) {
1077 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1078 }
1079 if (add_read_access_rule_by_path(arg_landlock, "/opt/")) {
1080 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1081 }
1082 if (add_execute_rule_by_path(arg_landlock, "/opt/")) {
1083 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1084 }
1085 if (add_read_access_rule_by_path(arg_landlock, "/usr/")) {
1086 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1087 }
1088 if (add_execute_rule_by_path(arg_landlock, "/usr/")) {
1089 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1090 }
1091 if (add_read_access_rule_by_path(arg_landlock, "/var/")) {
1092 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1093 }
1094 return 0;
1095 }
1096 if (strncmp(ptr, "landlock.proc ", 14) == 0) {
1097 if (strncmp(ptr+14, "no", 2) == 0) arg_landlock_proc = 0;
1098 else if (strncmp(ptr+14, "ro", 2) == 0) arg_landlock_proc = 1;
1099 else if (strncmp(ptr+14, "rw", 2) == 0) arg_landlock_proc = 2;
1100 return 0;
1101 }
1102 if (strncmp(ptr, "landlock.read ", 14) == 0) {
1051 if (arg_landlock == -1) arg_landlock = create_full_ruleset(); 1103 if (arg_landlock == -1) arg_landlock = create_full_ruleset();
1052 if (add_read_access_rule_by_path(arg_landlock, ptr+14)) { 1104 if (add_read_access_rule_by_path(arg_landlock, ptr+14)) {
1053 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); 1105 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1054 } 1106 }
1055 return 0; 1107 return 0;
1056 } 1108 }
1057 else if (strncmp(ptr, "landlock-write ", 15) == 0) { 1109 if (strncmp(ptr, "landlock.write ", 15) == 0) {
1058 if (arg_landlock == -1) arg_landlock = create_full_ruleset(); 1110 if (arg_landlock == -1) arg_landlock = create_full_ruleset();
1059 if (add_write_access_rule_by_path(arg_landlock, ptr+15,0)) { 1111 if (add_write_access_rule_by_path(arg_landlock, ptr+15)) {
1060 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); 1112 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1061 } 1113 }
1062 return 0; 1114 return 0;
1063 } 1115 }
1064 else if (strncmp(ptr, "landlock-restricted-write ", 26) == 0) { 1116 if (strncmp(ptr, "landlock.special ", 26) == 0) {
1065 if (arg_landlock == -1) arg_landlock = create_full_ruleset(); 1117 if (arg_landlock == -1) arg_landlock = create_full_ruleset();
1066 if (add_write_access_rule_by_path(arg_landlock, ptr+26,1)) { 1118 if (add_create_special_rule_by_path(arg_landlock, ptr+26)) {
1067 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); 1119 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
1068 } 1120 }
1069 return 0; 1121 return 0;
1070 } 1122 }
1071 else if (strncmp(ptr, "landlock-execute ", 17) == 0) { 1123 if (strncmp(ptr, "landlock.execute ", 17) == 0) {
1072 if (arg_landlock == -1) arg_landlock = create_full_ruleset(); 1124 if (arg_landlock == -1) arg_landlock = create_full_ruleset();
1073 if (add_execute_rule_by_path(arg_landlock, ptr+17)) { 1125 if (add_execute_rule_by_path(arg_landlock, ptr+17)) {
1074 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n"); 1126 fprintf(stderr,"An error has occured while adding a rule to the Landlock ruleset.\n");
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 014b31932..5fcccbd92 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -488,15 +488,6 @@ void start_application(int no_sandbox, int fd, char *set_sandbox_status) {
488#ifdef HAVE_APPARMOR 488#ifdef HAVE_APPARMOR
489 set_apparmor(); 489 set_apparmor();
490#endif 490#endif
491#ifdef HAVE_LANDLOCK
492 // set Landlock
493 if (arg_landlock >= 0) {
494 if (landlock_restrict_self(arg_landlock,0)) {
495 fprintf(stderr,"An error has occured while enabling Landlock self-restriction. Exiting...\n");
496 exit(1); // it isn't safe to continue if Landlock self-restriction was enabled and the "landlock_restrict_self" syscall has failed
497 }
498 }
499#endif
500 491
501 close_file_descriptors(); 492 close_file_descriptors();
502 493
@@ -519,6 +510,16 @@ void start_application(int no_sandbox, int fd, char *set_sandbox_status) {
519 printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD")); 510 printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD"));
520 } 511 }
521 512
513#ifdef HAVE_LANDLOCK
514 // set Landlock
515 if (arg_landlock >= 0) {
516 if (landlock_restrict_self(arg_landlock,0)) {
517 fprintf(stderr,"An error has occured while enabling Landlock self-restriction. Exiting...\n");
518 exit(1); // it isn't safe to continue if Landlock self-restriction was enabled and the "landlock_restrict_self" syscall has failed
519 }
520 }
521#endif
522
522 if (just_run_the_shell) { 523 if (just_run_the_shell) {
523 char *arg[2]; 524 char *arg[2];
524 arg[0] = cfg.usershell; 525 arg[0] = cfg.usershell;
@@ -1009,6 +1010,15 @@ int sandbox(void* sandbox_arg) {
1009 fs_proc_sys_dev_boot(); 1010 fs_proc_sys_dev_boot();
1010 1011
1011 //**************************** 1012 //****************************
1013 // Allow access to /proc
1014 //****************************
1015#ifdef HAVE_LANDLOCK
1016 if (arg_landlock>-1) {
1017 if (arg_landlock_proc >= 1) add_read_access_rule_by_path(arg_landlock, "/proc/");
1018 if (arg_landlock_proc == 2) add_write_access_rule_by_path(arg_landlock, "/proc/");
1019}
1020#endif
1021 //****************************
1012 // handle /mnt and /media 1022 // handle /mnt and /media
1013 //**************************** 1023 //****************************
1014 if (checkcfg(CFG_DISABLE_MNT)) 1024 if (checkcfg(CFG_DISABLE_MNT))
@@ -1103,9 +1113,12 @@ int sandbox(void* sandbox_arg) {
1103 //**************************** 1113 //****************************
1104 // rebuild etc directory, set dns 1114 // rebuild etc directory, set dns
1105 //**************************** 1115 //****************************
1106 if (!arg_writable_etc) 1116 if (!arg_writable_etc){
1107 fs_rebuild_etc(); 1117 fs_rebuild_etc();
1108 1118#ifdef HAVE_LANDLOCK
1119 if (arg_landlock>-1) add_read_access_rule_by_path(arg_landlock, "/etc/");
1120#endif
1121 }
1109 //**************************** 1122 //****************************
1110 // start dhcp client 1123 // start dhcp client
1111 //**************************** 1124 //****************************
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index 485d08ab0..e0751ef5c 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -122,10 +122,12 @@ static char *usage_str =
122 " --keep-dev-shm - /dev/shm directory is untouched (even with --private-dev).\n" 122 " --keep-dev-shm - /dev/shm directory is untouched (even with --private-dev).\n"
123 " --keep-fd - inherit open file descriptors to sandbox.\n" 123 " --keep-fd - inherit open file descriptors to sandbox.\n"
124 " --keep-var-tmp - /var/tmp directory is untouched.\n" 124 " --keep-var-tmp - /var/tmp directory is untouched.\n"
125 " --landlock-read=path - add a read access rule for the path to the Landlock ruleset.\n" 125 " --landlock - add basic rules to the Landlock ruleset.\n"
126 " --landlock-write=path - add a write access rule for the path to the Landlock ruleset.\n" 126 " --landlock.proc=no|ro|rw - add an access rule for /proc to the Landlock ruleset.\n"
127 " --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" 127 " --landlock.read=path - add a read access rule for the path to the Landlock ruleset.\n"
128 " --landlock-execute=path - add an execution-permitting rule for the path to the Landlock ruleset.\n" 128 " --landlock.write=path - add a write access rule for the path to the Landlock ruleset.\n"
129 " --landlock.special=path - add an access rule for creating FIFO pipes, Unix domain sockets and block devices for the path to the Landlock ruleset.\n"
130 " --landlock.execute=path - add an execution-permitting rule for the path to the Landlock ruleset.\n"
129 " --list - list all sandboxes.\n" 131 " --list - list all sandboxes.\n"
130#ifdef HAVE_FILE_TRANSFER 132#ifdef HAVE_FILE_TRANSFER
131 " --ls=name|pid dir_or_filename - list files in sandbox container.\n" 133 " --ls=name|pid dir_or_filename - list files in sandbox container.\n"
diff --git a/src/firejail/util.c b/src/firejail/util.c
index a01290cf2..b6a7ca08c 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -1338,6 +1338,10 @@ void close_all(int *keep_list, size_t sz) {
1338 if (keep) 1338 if (keep)
1339 continue; 1339 continue;
1340 1340
1341 // don't close the file descriptor of the Landlock ruleset -- it will be automatically closed by the landlock_restrict_self wrapper function
1342#ifdef HAVE_LANDLOCK
1343 if (fd == arg_landlock) continue;
1344#endif
1341 close(fd); 1345 close(fd);
1342 } 1346 }
1343 closedir(dir); 1347 closedir(dir);
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt
index 6e75aceed..1f543980e 100644
--- a/src/man/firejail-profile.txt
+++ b/src/man/firejail-profile.txt
@@ -499,23 +499,31 @@ Blacklist all Linux capabilities.
499Whitelist given Linux capabilities. 499Whitelist given Linux capabilities.
500#ifdef HAVE_LANDLOCK 500#ifdef HAVE_LANDLOCK
501.TP 501.TP
502\fBlandlock-read path 502\fBlandlock
503Create 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. 503Create a Landlock ruleset (if it doesn't already exist) and add basic access rules to it.
504.br
505.TP
506\fBlandlock.proc no|ro|rw
507Add an access rule for /proc directory (read-only if set to \fBro\fR and read-write if set to \fBrw\fR). The access rule for /proc is added after this directory is set up in the sandbox. Access rules for /proc set up with other Landlock-related profile options have no effect.
508.br
509.TP
510\fBlandlock.read path
511Create a Landlock ruleset (if it doesn't already exist) and add a read access rule for path.
504.br 512.br
505 513
506.TP 514.TP
507\fBlandlock-write path 515\fBlandlock.write path
508Create 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. 516Create a Landlock ruleset (if it doesn't already exist) and add a write access rule for path.
509.br 517.br
510 518
511.TP 519.TP
512\fBlandlock-restricted-write path 520\fBlandlock.special path
513Create 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. 521Create a Landlock ruleset (if it doesn't already exist) and add an access rule for creation of FIFO pipes, Unix-domain sockets and block devices beneath given path.
514.br 522.br
515 523
516.TP 524.TP
517\fBlandlock-execute path 525\fBlandlock.execute path
518Create 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. 526Create a Landlock ruleset (if it doesn't already exist) and add an execution permission rule for path.
519.br 527.br
520#endif 528#endif
521.TP 529.TP
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 7082fe0ab..7922a53d0 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -1146,29 +1146,37 @@ $ firejail --keep-var-tmp
1146 1146
1147#ifdef HAVE_LANDLOCK 1147#ifdef HAVE_LANDLOCK
1148.TP 1148.TP
1149\fB\-\-landlock-read=path 1149\fB\-\-landlock
1150Create 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. 1150Create a Landlock ruleset (if it doesn't already exist) and add basic access rules to it. See \fBLANDLOCK\fR section for more information.
1151.br
1152.TP
1153\fB\-\-landlock.proc=no|ro|rw
1154Add an access rule for /proc directory (read-only if set to \fBro\fR and read-write if set to \fBrw\fR). The access rule for /proc is added after this directory is set up in the sandbox. Access rules for /proc set up with other Landlock-related command-line options have no effect.
1155.br
1156.TP
1157\fB\-\-landlock.read=path
1158Create a Landlock ruleset (if it doesn't already exist) and add a read access rule for path.
1151.br 1159.br
1152 1160
1153.TP 1161.TP
1154\fB\-\-landlock-write=path 1162\fB\-\-landlock.write=path
1155Create 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. 1163Create a Landlock ruleset (if it doesn't already exist) and add a write access rule for path.
1156.br 1164.br
1157 1165
1158.TP 1166.TP
1159\fB\-\-landlock-restricted-write=path 1167\fB\-\-landlock.special=path
1160Create 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. 1168Create a Landlock ruleset (if it doesn't already exist) and add a permission rule to create FIFO pipes, Unix domain sockets and block devices beneath given path.
1161.br 1169.br
1162 1170
1163.TP 1171.TP
1164\fB\-\-landlock-execute=path 1172\fB\-\-landlock.execute=path
1165Create 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. 1173Create a Landlock ruleset (if it doesn't already exist) and add an execution permission rule for path.
1166.br 1174.br
1167 1175
1168.br 1176.br
1169Example: 1177Example:
1170.br 1178.br
1171$ firejail \-\-landlock-read=/ \-\-landlock-restricted-write=/home \-\-landlock-execute=/usr 1179$ firejail \-\-landlock.read=/ \-\-landlock.write=/home \-\-landlock.execute=/usr
1172#endif 1180#endif
1173 1181
1174.TP 1182.TP
@@ -3216,7 +3224,34 @@ To enable AppArmor confinement on top of your current Firejail security features
3216.br 3224.br
3217$ firejail --apparmor firefox 3225$ firejail --apparmor firefox
3218#endif 3226#endif
3227#ifdef HAVE_LANDLOCK
3228.SH LANDLOCK
3229.TP
3230Landlock is a Linux security module first introduced in the 5.13 version of Linux kernel. It allows unprivileged processes to restrict their access to the filesystem. Once imposed, these restrictions can never be removed, and all child processes created by a Landlock-restricted processes inherit these restrictions. Firejail supports Landlock as an additional sandboxing feature. It can be used to ensure that a sandboxed application can only access files and directories that it was explicitly allowed to access. Firejail supports populating the ruleset with both basic set of rules and with custom set of rules. Basic set of rules allows read-only access to /bin, /dev, /etc, /lib, /opt, /proc, /usr and /var, read-write access to the home directory, and allows execution of binaries located in /bin, /opt and /usr.
3231.br
3232
3233.TP
3234Important notes:
3235.br
3219 3236
3237.br
3238- A process can install a Landlock ruleset only if it has either \fBCAP_SYS_ADMIN\fR in its effective capability set, or the "No New Privileges" restriction enabled. Because of this, enabling the Landlock feature will also cause Firejail to enable the "No New Privileges" restriction, regardless of the profile or the \fB\-\-no\-new\-privs\fR command line option.
3239.br
3240
3241.br
3242- Access to the /proc directory is managed through the \fB\-\-landlock.proc\fR command line option.
3243
3244.br
3245- Access to the /etc directory is automatically allowed. To override this, use the \fB\-\-writable\-etc\fR command line option. You can also use the \fB\-\-private\-etc\fR option to restrict access to the /etc directory.
3246.br
3247
3248.TP
3249To enable Landlock self-restriction on top of your current Firejail security features, pass \fB\-\-landlock\fR flag to Firejail command line. You can also use \fB\-\-landlock.read\fR, \fB\-\-landlock.write\fR, \fB\-\-landlock.special\fR and \fB\-\-landlock.execute\fR options together with \fB\-\-landlock\fR or instead of it. Example:
3250.br
3251
3252.br
3253$ firejail --landlock --landlock.read=/media --landlock.proc=ro mc
3254#endif
3220.SH DESKTOP INTEGRATION 3255.SH DESKTOP INTEGRATION
3221A symbolic link to /usr/bin/firejail under the name of a program, will start the program in Firejail sandbox. 3256A symbolic link to /usr/bin/firejail under the name of a program, will start the program in Firejail sandbox.
3222The symbolic link should be placed in the first $PATH position. On most systems, a good place 3257The symbolic link should be placed in the first $PATH position. On most systems, a good place
diff --git a/src/zsh_completion/_firejail.in b/src/zsh_completion/_firejail.in
index da024eae5..ed7337762 100644
--- a/src/zsh_completion/_firejail.in
+++ b/src/zsh_completion/_firejail.in
@@ -105,10 +105,12 @@ _firejail_args=(
105 '--keep-dev-shm[/dev/shm directory is untouched (even with --private-dev)]' 105 '--keep-dev-shm[/dev/shm directory is untouched (even with --private-dev)]'
106 '--keep-fd[inherit open file descriptors to sandbox]: :' 106 '--keep-fd[inherit open file descriptors to sandbox]: :'
107 '--keep-var-tmp[/var/tmp directory is untouched]' 107 '--keep-var-tmp[/var/tmp directory is untouched]'
108 '--landlock-read=-[Landlock read access rule]: :_files' 108 '--landlock[Basic Landlock ruleset]'
109 '--landlock-write=-[Landlock write access rule]: :_files' 109 '--landlock.proc=-[Access to the /proc directory]: :(no ro rw)'
110 "--landlock-restricted-write=-[Landlock write access rule that doesn't include creation of FIFO pipes, sockets and block devices]: :_files" 110 '--landlock.read=-[Landlock read access rule]: :_files'
111 '--landlock-execute=-[Landlock execution-permitting rule]: :_files' 111 '--landlock.write=-[Landlock write access rule]: :_files'
112 "--landlock.special=-[Landlock access rule for creation of FIFO pipes, sockets and block devices]: :_files"
113 '--landlock.execute=-[Landlock execution-permitting rule]: :_files'
112 '--machine-id[spoof /etc/machine-id with a random id]' 114 '--machine-id[spoof /etc/machine-id with a random id]'
113 '--memory-deny-write-execute[seccomp filter to block attempts to create memory mappings that are both writable and executable]' 115 '--memory-deny-write-execute[seccomp filter to block attempts to create memory mappings that are both writable and executable]'
114 '*--mkdir=-[create a directory]:' 116 '*--mkdir=-[create a directory]:'