diff options
author | 2023-10-24 12:43:46 -0400 | |
---|---|---|
committer | 2023-11-07 17:55:13 -0300 | |
commit | 13b2c566df883269b55f77757bb50a5d2890ec20 (patch) | |
tree | 5c7ccc9d00886b93c4429a91671161fa6464f1f9 /src | |
parent | cleanup (diff) | |
download | firejail-13b2c566d.tar.gz firejail-13b2c566d.tar.zst firejail-13b2c566d.zip |
feature: add Landlock support
Based on 5315 by ChrysoliteAzalea.
It is based on the same underlying structure, but with a lot of
refactoring/simplification and with bugfixes and improvements.
Co-authored-by: Kelvin M. Klann <kmk3.code@protonmail.com>
Co-authored-by: Азалия Смарагдова <charming.flurry@yandex.ru>
Diffstat (limited to 'src')
-rw-r--r-- | src/bash_completion/firejail.bash_completion.in | 19 | ||||
-rw-r--r-- | src/firejail/checkcfg.c | 7 | ||||
-rw-r--r-- | src/firejail/firejail.h | 22 | ||||
-rw-r--r-- | src/firejail/landlock.c | 263 | ||||
-rw-r--r-- | src/firejail/main.c | 28 | ||||
-rw-r--r-- | src/firejail/profile.c | 38 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 22 | ||||
-rw-r--r-- | src/firejail/usage.c | 8 | ||||
-rw-r--r-- | src/firejail/util.c | 7 | ||||
-rw-r--r-- | src/man/firejail-profile.5.in | 31 | ||||
-rw-r--r-- | src/man/firejail.1.in | 87 | ||||
-rw-r--r-- | src/zsh_completion/_firejail.in | 5 |
12 files changed, 537 insertions, 0 deletions
diff --git a/src/bash_completion/firejail.bash_completion.in b/src/bash_completion/firejail.bash_completion.in index 98e3a035e..eab0f7df6 100644 --- a/src/bash_completion/firejail.bash_completion.in +++ b/src/bash_completion/firejail.bash_completion.in | |||
@@ -42,6 +42,25 @@ _firejail() | |||
42 | _filedir -d | 42 | _filedir -d |
43 | return 0 | 43 | return 0 |
44 | ;; | 44 | ;; |
45 | --landlock) | ||
46 | return 0 | ||
47 | ;; | ||
48 | --landlock.read) | ||
49 | _filedir | ||
50 | return 0 | ||
51 | ;; | ||
52 | --landlock.write) | ||
53 | _filedir | ||
54 | return 0 | ||
55 | ;; | ||
56 | --landlock.special) | ||
57 | _filedir | ||
58 | return 0 | ||
59 | ;; | ||
60 | --landlock.execute) | ||
61 | _filedir | ||
62 | return 0 | ||
63 | ;; | ||
45 | --tmpfs) | 64 | --tmpfs) |
46 | _filedir | 65 | _filedir |
47 | return 0 | 66 | return 0 |
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c index d2289bb40..7792c6541 100644 --- a/src/firejail/checkcfg.c +++ b/src/firejail/checkcfg.c | |||
@@ -363,6 +363,13 @@ static const char *const compiletime_support = | |||
363 | "disabled" | 363 | "disabled" |
364 | #endif | 364 | #endif |
365 | 365 | ||
366 | "\n\t- Landlock support is " | ||
367 | #ifdef HAVE_LANDLOCK | ||
368 | "enabled" | ||
369 | #else | ||
370 | "disabled" | ||
371 | #endif | ||
372 | |||
366 | "\n\t- networking support is " | 373 | "\n\t- networking support is " |
367 | #ifdef HAVE_NETWORK | 374 | #ifdef HAVE_NETWORK |
368 | "enabled" | 375 | "enabled" |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index c791913ea..efeda7228 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -281,6 +281,9 @@ extern int arg_overlay; // overlay option | |||
281 | extern int arg_overlay_keep; // place overlay diff in a known directory | 281 | extern int arg_overlay_keep; // place overlay diff in a known directory |
282 | extern int arg_overlay_reuse; // allow the reuse of overlays | 282 | extern int arg_overlay_reuse; // allow the reuse of overlays |
283 | 283 | ||
284 | extern int arg_landlock; // add basic Landlock rules | ||
285 | extern int arg_landlock_proc; // 0 - no access; 1 -read-only; 2 - read-write | ||
286 | |||
284 | extern int arg_seccomp; // enable default seccomp filter | 287 | extern int arg_seccomp; // enable default seccomp filter |
285 | extern int arg_seccomp32; // enable default seccomp filter for 32 bit arch | 288 | extern int arg_seccomp32; // enable default seccomp filter for 32 bit arch |
286 | extern int arg_seccomp_postexec; // need postexec ld.preload library? | 289 | extern int arg_seccomp_postexec; // need postexec ld.preload library? |
@@ -950,4 +953,23 @@ void run_ids(int argc, char **argv); | |||
950 | // oom.c | 953 | // oom.c |
951 | void oom_set(const char *oom_string); | 954 | void oom_set(const char *oom_string); |
952 | 955 | ||
956 | // landlock.c | ||
957 | #ifdef HAVE_LANDLOCK | ||
958 | int ll_get_fd(void); | ||
959 | int ll_read(const char *allowed_path); | ||
960 | int ll_write(const char *allowed_path); | ||
961 | int ll_special(const char *allowed_path); | ||
962 | int ll_exec(const char *allowed_path); | ||
963 | int ll_basic_system(void); | ||
964 | int ll_restrict(__u32 flags); | ||
965 | #else | ||
966 | static inline int ll_get_fd(void) { return -1; } | ||
967 | static inline int ll_read(...) { return 0; } | ||
968 | static inline int ll_write(...) { return 0; } | ||
969 | static inline int ll_special(...) { return 0; } | ||
970 | static inline int ll_exec(...) { return 0; } | ||
971 | static inline int ll_basic_system(void) { return 0; } | ||
972 | static inline int ll_restrict(...) { return 0; } | ||
973 | #endif /* HAVE_LANDLOCK */ | ||
974 | |||
953 | #endif | 975 | #endif |
diff --git a/src/firejail/landlock.c b/src/firejail/landlock.c new file mode 100644 index 000000000..b5f4140c5 --- /dev/null +++ b/src/firejail/landlock.c | |||
@@ -0,0 +1,263 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2023 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifdef HAVE_LANDLOCK | ||
22 | #include "firejail.h" | ||
23 | #include <linux/landlock.h> | ||
24 | #include <sys/prctl.h> | ||
25 | #include <sys/syscall.h> | ||
26 | #include <sys/types.h> | ||
27 | #include <errno.h> | ||
28 | #include <fcntl.h> | ||
29 | |||
30 | static int ll_ruleset_fd = -1; | ||
31 | |||
32 | int ll_get_fd(void) { | ||
33 | return ll_ruleset_fd; | ||
34 | } | ||
35 | |||
36 | #ifndef landlock_create_ruleset | ||
37 | static inline int | ||
38 | landlock_create_ruleset(const struct landlock_ruleset_attr *const attr, | ||
39 | const size_t size, const __u32 flags) { | ||
40 | return syscall(__NR_landlock_create_ruleset, attr, size, flags); | ||
41 | } | ||
42 | #endif | ||
43 | |||
44 | #ifndef landlock_add_rule | ||
45 | static inline int | ||
46 | landlock_add_rule(const int ruleset_fd, | ||
47 | const enum landlock_rule_type rule_type, | ||
48 | const void *const rule_attr, | ||
49 | const __u32 flags) { | ||
50 | return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, | ||
51 | rule_attr, flags); | ||
52 | } | ||
53 | #endif | ||
54 | |||
55 | #ifndef landlock_restrict_self | ||
56 | static inline int | ||
57 | landlock_restrict_self(const int ruleset_fd, const __u32 flags) { | ||
58 | return syscall(__NR_landlock_restrict_self, ruleset_fd, flags); | ||
59 | } | ||
60 | #endif | ||
61 | |||
62 | static int ll_create_full_ruleset() { | ||
63 | struct landlock_ruleset_attr attr; | ||
64 | attr.handled_access_fs = | ||
65 | LANDLOCK_ACCESS_FS_EXECUTE | | ||
66 | LANDLOCK_ACCESS_FS_MAKE_BLOCK | | ||
67 | LANDLOCK_ACCESS_FS_MAKE_CHAR | | ||
68 | LANDLOCK_ACCESS_FS_MAKE_DIR | | ||
69 | LANDLOCK_ACCESS_FS_MAKE_FIFO | | ||
70 | LANDLOCK_ACCESS_FS_MAKE_REG | | ||
71 | LANDLOCK_ACCESS_FS_MAKE_SOCK | | ||
72 | LANDLOCK_ACCESS_FS_MAKE_SYM | | ||
73 | LANDLOCK_ACCESS_FS_READ_DIR | | ||
74 | LANDLOCK_ACCESS_FS_READ_FILE | | ||
75 | LANDLOCK_ACCESS_FS_REMOVE_DIR | | ||
76 | LANDLOCK_ACCESS_FS_REMOVE_FILE | | ||
77 | LANDLOCK_ACCESS_FS_WRITE_FILE; | ||
78 | |||
79 | ll_ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); | ||
80 | if (ll_ruleset_fd < 0) { | ||
81 | fprintf(stderr, "Error: failed to create a Landlock ruleset: %s\n", | ||
82 | strerror(errno)); | ||
83 | } | ||
84 | return ll_ruleset_fd; | ||
85 | } | ||
86 | |||
87 | int ll_read(const char *allowed_path) { | ||
88 | if (ll_ruleset_fd == -1) | ||
89 | ll_ruleset_fd = ll_create_full_ruleset(); | ||
90 | |||
91 | int error; | ||
92 | int allowed_fd = open(allowed_path, O_PATH | O_CLOEXEC); | ||
93 | if (allowed_fd < 0) { | ||
94 | if (arg_debug) { | ||
95 | fprintf(stderr, "%s: failed to open %s: %s\n", | ||
96 | __func__, allowed_path, strerror(errno)); | ||
97 | } | ||
98 | return 0; | ||
99 | } | ||
100 | struct landlock_path_beneath_attr target; | ||
101 | target.parent_fd = allowed_fd; | ||
102 | target.allowed_access = | ||
103 | LANDLOCK_ACCESS_FS_READ_DIR | | ||
104 | LANDLOCK_ACCESS_FS_READ_FILE; | ||
105 | |||
106 | error = landlock_add_rule(ll_ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, | ||
107 | &target, 0); | ||
108 | if (error) { | ||
109 | fprintf(stderr, "Error: %s: failed to add Landlock rule for %s: %s\n", | ||
110 | __func__, allowed_path, strerror(errno)); | ||
111 | } | ||
112 | close(allowed_fd); | ||
113 | return error; | ||
114 | } | ||
115 | |||
116 | int ll_write(const char *allowed_path) { | ||
117 | if (ll_ruleset_fd == -1) | ||
118 | ll_ruleset_fd = ll_create_full_ruleset(); | ||
119 | |||
120 | int error; | ||
121 | int allowed_fd = open(allowed_path, O_PATH | O_CLOEXEC); | ||
122 | if (allowed_fd < 0) { | ||
123 | if (arg_debug) { | ||
124 | fprintf(stderr, "%s: failed to open %s: %s\n", | ||
125 | __func__, allowed_path, strerror(errno)); | ||
126 | } | ||
127 | return 0; | ||
128 | } | ||
129 | struct landlock_path_beneath_attr target; | ||
130 | target.parent_fd = allowed_fd; | ||
131 | target.allowed_access = | ||
132 | LANDLOCK_ACCESS_FS_MAKE_DIR | | ||
133 | LANDLOCK_ACCESS_FS_MAKE_REG | | ||
134 | LANDLOCK_ACCESS_FS_MAKE_SYM | | ||
135 | LANDLOCK_ACCESS_FS_REMOVE_DIR | | ||
136 | LANDLOCK_ACCESS_FS_REMOVE_FILE | | ||
137 | LANDLOCK_ACCESS_FS_WRITE_FILE; | ||
138 | |||
139 | error = landlock_add_rule(ll_ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, | ||
140 | &target, 0); | ||
141 | if (error) { | ||
142 | fprintf(stderr, "Error: %s: failed to add Landlock rule for %s: %s\n", | ||
143 | __func__, allowed_path, strerror(errno)); | ||
144 | } | ||
145 | close(allowed_fd); | ||
146 | return error; | ||
147 | } | ||
148 | |||
149 | int ll_special(const char *allowed_path) { | ||
150 | if (ll_ruleset_fd == -1) | ||
151 | ll_ruleset_fd = ll_create_full_ruleset(); | ||
152 | |||
153 | int error; | ||
154 | int allowed_fd = open(allowed_path, O_PATH | O_CLOEXEC); | ||
155 | if (allowed_fd < 0) { | ||
156 | if (arg_debug) { | ||
157 | fprintf(stderr, "%s: failed to open %s: %s\n", | ||
158 | __func__, allowed_path, strerror(errno)); | ||
159 | } | ||
160 | return 0; | ||
161 | } | ||
162 | struct landlock_path_beneath_attr target; | ||
163 | target.parent_fd = allowed_fd; | ||
164 | target.allowed_access = | ||
165 | LANDLOCK_ACCESS_FS_MAKE_BLOCK | | ||
166 | LANDLOCK_ACCESS_FS_MAKE_CHAR | | ||
167 | LANDLOCK_ACCESS_FS_MAKE_FIFO | | ||
168 | LANDLOCK_ACCESS_FS_MAKE_SOCK; | ||
169 | |||
170 | error = landlock_add_rule(ll_ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, | ||
171 | &target, 0); | ||
172 | if (error) { | ||
173 | fprintf(stderr, "Error: %s: failed to add Landlock rule for %s: %s\n", | ||
174 | __func__, allowed_path, strerror(errno)); | ||
175 | } | ||
176 | close(allowed_fd); | ||
177 | return error; | ||
178 | } | ||
179 | |||
180 | int ll_exec(const char *allowed_path) { | ||
181 | if (ll_ruleset_fd == -1) | ||
182 | ll_ruleset_fd = ll_create_full_ruleset(); | ||
183 | |||
184 | int error; | ||
185 | int allowed_fd = open(allowed_path, O_PATH | O_CLOEXEC); | ||
186 | if (allowed_fd < 0) { | ||
187 | if (arg_debug) { | ||
188 | fprintf(stderr, "%s: failed to open %s: %s\n", | ||
189 | __func__, allowed_path, strerror(errno)); | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
193 | struct landlock_path_beneath_attr target; | ||
194 | target.parent_fd = allowed_fd; | ||
195 | target.allowed_access = | ||
196 | LANDLOCK_ACCESS_FS_EXECUTE; | ||
197 | |||
198 | error = landlock_add_rule(ll_ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, | ||
199 | &target, 0); | ||
200 | if (error) { | ||
201 | fprintf(stderr, "Error: %s: failed to add Landlock rule for %s: %s\n", | ||
202 | __func__, allowed_path, strerror(errno)); | ||
203 | } | ||
204 | close(allowed_fd); | ||
205 | return error; | ||
206 | } | ||
207 | |||
208 | int ll_basic_system(void) { | ||
209 | assert(cfg.homedir); | ||
210 | |||
211 | if (ll_ruleset_fd == -1) | ||
212 | ll_ruleset_fd = ll_create_full_ruleset(); | ||
213 | |||
214 | int error = | ||
215 | ll_read("/bin/") || | ||
216 | ll_read("/dev/") || | ||
217 | ll_read("/etc/") || | ||
218 | ll_read("/lib/") || | ||
219 | ll_read("/opt/") || | ||
220 | ll_read("/usr/") || | ||
221 | ll_read("/var/") || | ||
222 | ll_read(cfg.homedir) || | ||
223 | |||
224 | ll_write("/dev/") || | ||
225 | ll_write(cfg.homedir) || | ||
226 | |||
227 | ll_exec("/bin/") || | ||
228 | ll_exec("/lib/") || | ||
229 | ll_exec("/opt/") || | ||
230 | ll_exec("/usr/"); | ||
231 | |||
232 | if (error) { | ||
233 | fprintf(stderr, "Error: %s: failed to set --landlock rules\n", | ||
234 | __func__); | ||
235 | } | ||
236 | return error; | ||
237 | } | ||
238 | |||
239 | int ll_restrict(__u32 flags) { | ||
240 | if (ll_ruleset_fd == -1) | ||
241 | return 0; | ||
242 | |||
243 | int error; | ||
244 | error = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | ||
245 | if (error) { | ||
246 | fprintf(stderr, "Error: %s: failed to restrict privileges: %s\n", | ||
247 | __func__, strerror(errno)); | ||
248 | goto out; | ||
249 | } | ||
250 | error = landlock_restrict_self(ll_ruleset_fd, flags); | ||
251 | if (error) { | ||
252 | fprintf(stderr, "Error: %s: failed to enforce Landlock: %s\n", | ||
253 | __func__, strerror(errno)); | ||
254 | goto out; | ||
255 | } | ||
256 | if (arg_debug) | ||
257 | printf("%s: Enforcing Landlock\n", __func__); | ||
258 | out: | ||
259 | close(ll_ruleset_fd); | ||
260 | return error; | ||
261 | } | ||
262 | |||
263 | #endif /* HAVE_LANDLOCK */ | ||
diff --git a/src/firejail/main.c b/src/firejail/main.c index 0c9c80137..df31fe2ce 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -75,6 +75,9 @@ int arg_overlay = 0; // overlay option | |||
75 | int arg_overlay_keep = 0; // place overlay diff in a known directory | 75 | int arg_overlay_keep = 0; // place overlay diff in a known directory |
76 | int arg_overlay_reuse = 0; // allow the reuse of overlays | 76 | int arg_overlay_reuse = 0; // allow the reuse of overlays |
77 | 77 | ||
78 | int arg_landlock = 0; // add basic Landlock rules | ||
79 | int arg_landlock_proc = 2; // 0 - no access; 1 -read-only; 2 - read-write | ||
80 | |||
78 | int arg_seccomp = 0; // enable default seccomp filter | 81 | int arg_seccomp = 0; // enable default seccomp filter |
79 | int arg_seccomp32 = 0; // enable default seccomp filter for 32 bit arch | 82 | int arg_seccomp32 = 0; // enable default seccomp filter for 32 bit arch |
80 | int arg_seccomp_postexec = 0; // need postexec ld.preload library? | 83 | int arg_seccomp_postexec = 0; // need postexec ld.preload library? |
@@ -1500,6 +1503,31 @@ int main(int argc, char **argv, char **envp) { | |||
1500 | else | 1503 | else |
1501 | exit_err_feature("seccomp"); | 1504 | exit_err_feature("seccomp"); |
1502 | } | 1505 | } |
1506 | #ifdef HAVE_LANDLOCK | ||
1507 | else if (strcmp(argv[i], "--landlock") == 0) | ||
1508 | arg_landlock = 1; | ||
1509 | else if (strncmp(argv[i], "--landlock.proc=", 16) == 0) { | ||
1510 | if (strncmp(argv[i] + 16, "no", 2) == 0) | ||
1511 | arg_landlock_proc = 0; | ||
1512 | else if (strncmp(argv[i] + 16, "ro", 2) == 0) | ||
1513 | arg_landlock_proc = 1; | ||
1514 | else if (strncmp(argv[i] + 16, "rw", 2) == 0) | ||
1515 | arg_landlock_proc = 2; | ||
1516 | else { | ||
1517 | fprintf(stderr, "Error: invalid landlock.proc value: %s\n", | ||
1518 | argv[i] + 16); | ||
1519 | exit(1); | ||
1520 | } | ||
1521 | } | ||
1522 | else if (strncmp(argv[i], "--landlock.read=", 16) == 0) | ||
1523 | ll_read(argv[i] + 16); | ||
1524 | else if (strncmp(argv[i], "--landlock.write=", 17) == 0) | ||
1525 | ll_write(argv[i] + 17); | ||
1526 | else if (strncmp(argv[i], "--landlock.special=", 19) == 0) | ||
1527 | ll_special(argv[i] + 19); | ||
1528 | else if (strncmp(argv[i], "--landlock.execute=", 19) == 0) | ||
1529 | ll_exec(argv[i] + 19); | ||
1530 | #endif | ||
1503 | else if (strcmp(argv[i], "--memory-deny-write-execute") == 0) { | 1531 | else if (strcmp(argv[i], "--memory-deny-write-execute") == 0) { |
1504 | if (checkcfg(CFG_SECCOMP)) | 1532 | if (checkcfg(CFG_SECCOMP)) |
1505 | arg_memory_deny_write_execute = 1; | 1533 | arg_memory_deny_write_execute = 1; |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index a250e5611..08804c5f3 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -1077,6 +1077,44 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1077 | return 0; | 1077 | return 0; |
1078 | } | 1078 | } |
1079 | 1079 | ||
1080 | #ifdef HAVE_LANDLOCK | ||
1081 | // Landlock ruleset paths | ||
1082 | if (strcmp(ptr, "landlock") == 0) { | ||
1083 | arg_landlock = 1; | ||
1084 | return 0; | ||
1085 | } | ||
1086 | if (strncmp(ptr, "landlock.proc ", 14) == 0) { | ||
1087 | if (strncmp(ptr + 14, "no", 2) == 0) | ||
1088 | arg_landlock_proc = 0; | ||
1089 | else if (strncmp(ptr + 14, "ro", 2) == 0) | ||
1090 | arg_landlock_proc = 1; | ||
1091 | else if (strncmp(ptr + 14, "rw", 2) == 0) | ||
1092 | arg_landlock_proc = 2; | ||
1093 | else { | ||
1094 | fprintf(stderr, "Error: invalid landlock.proc value: %s\n", | ||
1095 | ptr + 14); | ||
1096 | exit(1); | ||
1097 | } | ||
1098 | return 0; | ||
1099 | } | ||
1100 | if (strncmp(ptr, "landlock.read ", 14) == 0) { | ||
1101 | ll_read(ptr + 14); | ||
1102 | return 0; | ||
1103 | } | ||
1104 | if (strncmp(ptr, "landlock.write ", 15) == 0) { | ||
1105 | ll_write(ptr + 15); | ||
1106 | return 0; | ||
1107 | } | ||
1108 | if (strncmp(ptr, "landlock.special ", 17) == 0) { | ||
1109 | ll_special(ptr + 17); | ||
1110 | return 0; | ||
1111 | } | ||
1112 | if (strncmp(ptr, "landlock.execute ", 17) == 0) { | ||
1113 | ll_exec(ptr + 17); | ||
1114 | return 0; | ||
1115 | } | ||
1116 | #endif | ||
1117 | |||
1080 | // memory deny write&execute | 1118 | // memory deny write&execute |
1081 | if (strcmp(ptr, "memory-deny-write-execute") == 0) { | 1119 | if (strcmp(ptr, "memory-deny-write-execute") == 0) { |
1082 | if (checkcfg(CFG_SECCOMP)) | 1120 | if (checkcfg(CFG_SECCOMP)) |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 827be5d85..dbc115137 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -516,6 +516,28 @@ void start_application(int no_sandbox, int fd, char *set_sandbox_status) { | |||
516 | printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD")); | 516 | printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD")); |
517 | } | 517 | } |
518 | 518 | ||
519 | #ifdef HAVE_LANDLOCK | ||
520 | //**************************** | ||
521 | // Configure Landlock | ||
522 | //**************************** | ||
523 | if (arg_landlock) | ||
524 | ll_basic_system(); | ||
525 | |||
526 | if (ll_get_fd() != -1) { | ||
527 | if (arg_landlock_proc >= 1) | ||
528 | ll_read("/proc/"); | ||
529 | if (arg_landlock_proc == 2) | ||
530 | ll_write("/proc/"); | ||
531 | } | ||
532 | |||
533 | if (ll_restrict(0)) { | ||
534 | // It isn't safe to continue if Landlock self-restriction was | ||
535 | // enabled and the "landlock_restrict_self" syscall has failed. | ||
536 | fprintf(stderr, "Error: ll_restrict() failed, exiting...\n"); | ||
537 | exit(1); | ||
538 | } | ||
539 | #endif | ||
540 | |||
519 | if (just_run_the_shell) { | 541 | if (just_run_the_shell) { |
520 | char *arg[2]; | 542 | char *arg[2]; |
521 | arg[0] = cfg.usershell; | 543 | arg[0] = cfg.usershell; |
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index e8758c807..5f9185da9 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -133,6 +133,14 @@ static const char *const usage_str = | |||
133 | " --keep-fd - inherit open file descriptors to sandbox.\n" | 133 | " --keep-fd - inherit open file descriptors to sandbox.\n" |
134 | " --keep-shell-rc - do not copy shell rc files from /etc/skel\n" | 134 | " --keep-shell-rc - do not copy shell rc files from /etc/skel\n" |
135 | " --keep-var-tmp - /var/tmp directory is untouched.\n" | 135 | " --keep-var-tmp - /var/tmp directory is untouched.\n" |
136 | #ifdef HAVE_LANDLOCK | ||
137 | " --landlock - add basic rules to the Landlock ruleset.\n" | ||
138 | " --landlock.proc=no|ro|rw - add an access rule for /proc to the Landlock ruleset.\n" | ||
139 | " --landlock.read=path - add a read access rule for the path to the Landlock ruleset.\n" | ||
140 | " --landlock.write=path - add a write access rule for the path to the Landlock ruleset.\n" | ||
141 | " --landlock.special=path - add an access rule for the path to the Landlock ruleset for creating block/char devices, named pipes and sockets.\n" | ||
142 | " --landlock.execute=path - add an execute access rule for the path to the Landlock ruleset.\n" | ||
143 | #endif | ||
136 | " --list - list all sandboxes.\n" | 144 | " --list - list all sandboxes.\n" |
137 | #ifdef HAVE_FILE_TRANSFER | 145 | #ifdef HAVE_FILE_TRANSFER |
138 | " --ls=name|pid dir_or_filename - list files in sandbox container.\n" | 146 | " --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 bd32181b5..c0f30931c 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -1338,6 +1338,13 @@ void close_all(int *keep_list, size_t sz) { | |||
1338 | if (keep) | 1338 | if (keep) |
1339 | continue; | 1339 | continue; |
1340 | 1340 | ||
1341 | #ifdef HAVE_LANDLOCK | ||
1342 | // Don't close the file descriptor of the Landlock ruleset; it | ||
1343 | // will be automatically closed by the "ll_restrict" wrapper | ||
1344 | // function. | ||
1345 | if (fd == ll_get_fd()) | ||
1346 | continue; | ||
1347 | #endif | ||
1341 | close(fd); | 1348 | close(fd); |
1342 | } | 1349 | } |
1343 | closedir(dir); | 1350 | closedir(dir); |
diff --git a/src/man/firejail-profile.5.in b/src/man/firejail-profile.5.in index 3a678b14f..76f5e4d20 100644 --- a/src/man/firejail-profile.5.in +++ b/src/man/firejail-profile.5.in | |||
@@ -507,6 +507,37 @@ Blacklist all Linux capabilities. | |||
507 | .TP | 507 | .TP |
508 | \fBcaps.keep capability,capability,capability | 508 | \fBcaps.keep capability,capability,capability |
509 | Whitelist given Linux capabilities. | 509 | Whitelist given Linux capabilities. |
510 | #ifdef HAVE_LANDLOCK | ||
511 | .TP | ||
512 | \fBlandlock | ||
513 | Create a Landlock ruleset (if it doesn't already exist) and add basic access | ||
514 | rules to it. | ||
515 | .TP | ||
516 | \fBlandlock.proc no|ro|rw | ||
517 | Add an access rule for /proc directory (read-only if set to \fBro\fR and | ||
518 | read-write if set to \fBrw\fR). | ||
519 | The access rule for /proc is added after this directory is set up in the | ||
520 | sandbox. | ||
521 | Access rules for /proc set up with other Landlock-related profile options have | ||
522 | no effect. | ||
523 | .TP | ||
524 | \fBlandlock.read path | ||
525 | Create a Landlock ruleset (if it doesn't already exist) and add a read access | ||
526 | rule for path. | ||
527 | .TP | ||
528 | \fBlandlock.write path | ||
529 | Create a Landlock ruleset (if it doesn't already exist) and add a write access | ||
530 | rule for path. | ||
531 | .TP | ||
532 | \fBlandlock.special path | ||
533 | Create a Landlock ruleset (if it doesn't already exist) and add a rule that | ||
534 | allows the creation of block devices, character devices, named pipes (FIFOs) | ||
535 | and Unix domain sockets beneath given path. | ||
536 | .TP | ||
537 | \fBlandlock.execute path | ||
538 | Create a Landlock ruleset (if it doesn't already exist) and add an execution | ||
539 | permission rule for path. | ||
540 | #endif | ||
510 | .TP | 541 | .TP |
511 | \fBmemory-deny-write-execute | 542 | \fBmemory-deny-write-execute |
512 | Install a seccomp filter to block attempts to create memory mappings | 543 | Install a seccomp filter to block attempts to create memory mappings |
diff --git a/src/man/firejail.1.in b/src/man/firejail.1.in index 06969e851..d5a00c41b 100644 --- a/src/man/firejail.1.in +++ b/src/man/firejail.1.in | |||
@@ -1243,6 +1243,52 @@ Example: | |||
1243 | .br | 1243 | .br |
1244 | $ firejail --keep-var-tmp | 1244 | $ firejail --keep-var-tmp |
1245 | 1245 | ||
1246 | #ifdef HAVE_LANDLOCK | ||
1247 | .TP | ||
1248 | \fB\-\-landlock | ||
1249 | Create a Landlock ruleset (if it doesn't already exist) and add basic access | ||
1250 | rules to it. | ||
1251 | The basic set of rules applies the following access permissions: | ||
1252 | .PP | ||
1253 | .RS | ||
1254 | - read: /bin, /dev, /etc, /lib, /opt, /proc, /usr, /var | ||
1255 | .br | ||
1256 | - write: /dev, /proc | ||
1257 | .br | ||
1258 | - exec: /bin, /lib, /opt, /usr | ||
1259 | .RE | ||
1260 | .PP | ||
1261 | See the \fBLANDLOCK\fR section for more information. | ||
1262 | .TP | ||
1263 | \fB\-\-landlock.proc=no|ro|rw | ||
1264 | Add an access rule for /proc directory (read-only if set to \fBro\fR and | ||
1265 | read-write if set to \fBrw\fR). | ||
1266 | The access rule for /proc is added after this directory is set up in the | ||
1267 | sandbox. | ||
1268 | Access rules for /proc set up with other Landlock-related command-line options | ||
1269 | have no effect. | ||
1270 | .TP | ||
1271 | \fB\-\-landlock.read=path | ||
1272 | Create a Landlock ruleset (if it doesn't already exist) and add a read access | ||
1273 | rule for path. | ||
1274 | .TP | ||
1275 | \fB\-\-landlock.write=path | ||
1276 | Create a Landlock ruleset (if it doesn't already exist) and add a write access | ||
1277 | rule for path. | ||
1278 | .TP | ||
1279 | \fB\-\-landlock.special=path | ||
1280 | Create a Landlock ruleset (if it doesn't already exist) and add a rule that | ||
1281 | allows the creation of block devices, character devices, named pipes (FIFOs) | ||
1282 | and Unix domain sockets beneath given path. | ||
1283 | .TP | ||
1284 | \fB\-\-landlock.execute=path | ||
1285 | Create a Landlock ruleset (if it doesn't already exist) and add an execution | ||
1286 | permission rule for path. | ||
1287 | .PP | ||
1288 | Example: | ||
1289 | .PP | ||
1290 | $ firejail \-\-landlock.read=/ \-\-landlock.write=/home \-\-landlock.execute=/usr | ||
1291 | #endif | ||
1246 | .TP | 1292 | .TP |
1247 | \fB\-\-list | 1293 | \fB\-\-list |
1248 | List all sandboxes, see \fBMONITORING\fR section for more details. | 1294 | List all sandboxes, see \fBMONITORING\fR section for more details. |
@@ -3365,6 +3411,47 @@ To enable AppArmor confinement on top of your current Firejail security features | |||
3365 | $ firejail --apparmor firefox | 3411 | $ firejail --apparmor firefox |
3366 | #endif | 3412 | #endif |
3367 | 3413 | ||
3414 | #ifdef HAVE_LANDLOCK | ||
3415 | .SH LANDLOCK | ||
3416 | Landlock is a Linux security module first introduced in version 5.13 of the | ||
3417 | Linux kernel. | ||
3418 | It allows unprivileged processes to restrict their access to the filesystem. | ||
3419 | Once imposed, these restrictions can never be removed, and all child processes | ||
3420 | created by a Landlock-restricted processes inherit these restrictions. | ||
3421 | Firejail supports Landlock as an additional sandboxing feature. | ||
3422 | It can be used to ensure that a sandboxed application can only access files and | ||
3423 | directories that it was explicitly allowed to access. | ||
3424 | Firejail supports populating the ruleset with both a basic set of rules (see | ||
3425 | \fB\-\-landlock\fR) and with a custom set of rules. | ||
3426 | .TP | ||
3427 | Important notes: | ||
3428 | .PP | ||
3429 | .RS | ||
3430 | - A process can install a Landlock ruleset only if it has either | ||
3431 | \fBCAP_SYS_ADMIN\fR in its effective capability set, or the "No New | ||
3432 | Privileges" restriction enabled. | ||
3433 | Because of this, enabling the Landlock feature will also cause Firejail to | ||
3434 | enable the "No New Privileges" restriction, regardless of the profile or the | ||
3435 | \fB\-\-no\-new\-privs\fR command line option. | ||
3436 | .PP | ||
3437 | - Access to the /proc directory is managed through the \fB\-\-landlock.proc\fR | ||
3438 | command line option. | ||
3439 | .PP | ||
3440 | - Access to the /etc directory is automatically allowed. | ||
3441 | To override this, use the \fB\-\-writable\-etc\fR command line option. | ||
3442 | You can also use the \fB\-\-private\-etc\fR option to restrict access to the | ||
3443 | /etc directory. | ||
3444 | .RE | ||
3445 | .PP | ||
3446 | To enable Landlock self-restriction on top of your current Firejail security | ||
3447 | features, pass \fB\-\-landlock\fR flag to Firejail command line. | ||
3448 | You can also use \fB\-\-landlock.read\fR, \fB\-\-landlock.write\fR, | ||
3449 | \fB\-\-landlock.special\fR and \fB\-\-landlock.execute\fR options together with | ||
3450 | \fB\-\-landlock\fR or instead of it. | ||
3451 | Example: | ||
3452 | .PP | ||
3453 | $ firejail \-\-landlock \-\-landlock.read=/media \-\-landlock.proc=ro mc | ||
3454 | #endif | ||
3368 | .SH DESKTOP INTEGRATION | 3455 | .SH DESKTOP INTEGRATION |
3369 | A symbolic link to /usr/bin/firejail under the name of a program, will start the program in Firejail sandbox. | 3456 | A symbolic link to /usr/bin/firejail under the name of a program, will start the program in Firejail sandbox. |
3370 | The symbolic link should be placed in the first $PATH position. On most systems, a good place | 3457 | The 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 7e87bb991..89cb1b84c 100644 --- a/src/zsh_completion/_firejail.in +++ b/src/zsh_completion/_firejail.in | |||
@@ -106,6 +106,11 @@ _firejail_args=( | |||
106 | '--keep-fd[inherit open file descriptors to sandbox]: :' | 106 | '--keep-fd[inherit open file descriptors to sandbox]: :' |
107 | '--keep-shell-rc[do not copy shell rc files from /etc/skel]' | 107 | '--keep-shell-rc[do not copy shell rc files from /etc/skel]' |
108 | '--keep-var-tmp[/var/tmp directory is untouched]' | 108 | '--keep-var-tmp[/var/tmp directory is untouched]' |
109 | '--landlock.proc=-[add an access rule for /proc to the Landlock ruleset]: :(no ro rw)' | ||
110 | '--landlock.read=-[add a read access rule for the path to the Landlock ruleset]: :_files' | ||
111 | '--landlock.write=-[add a write access rule for the path to the Landlock ruleset]: :_files' | ||
112 | '--landlock.special=-[add an access rule for the path to the Landlock ruleset for creating block/char devices, named pipes and sockets]: :_files' | ||
113 | '--landlock.execute=-[add an execute access rule for the path to the Landlock ruleset]: :_files' | ||
109 | '--machine-id[spoof /etc/machine-id with a random id]' | 114 | '--machine-id[spoof /etc/machine-id with a random id]' |
110 | '--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]' |
111 | '*--mkdir=-[create a directory]:' | 116 | '*--mkdir=-[create a directory]:' |