diff options
author | netblue30 <netblue30@protonmail.com> | 2023-12-04 09:18:05 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-04 09:18:05 -0500 |
commit | 9ba5c8d50b2b00244cb539809f8da7ba32043fa4 (patch) | |
tree | ff28ac831ce0d11591b2c49f66ee9b92ae1c8b8e | |
parent | Merge pull request #6104 from kmk3/ci-enable-sort-py (diff) | |
parent | landlock: detect support at runtime (diff) | |
download | firejail-9ba5c8d50b2b00244cb539809f8da7ba32043fa4.tar.gz firejail-9ba5c8d50b2b00244cb539809f8da7ba32043fa4.tar.zst firejail-9ba5c8d50b2b00244cb539809f8da7ba32043fa4.zip |
Merge pull request #6078 from kmk3/landlock_v3
feature: add Landlock support
-rw-r--r-- | README | 3 | ||||
-rw-r--r-- | config.mk.in | 2 | ||||
-rwxr-xr-x | configure | 86 | ||||
-rw-r--r-- | configure.ac | 12 | ||||
-rw-r--r-- | contrib/syntax/lists/profile_commands_arg0.list | 1 | ||||
-rw-r--r-- | contrib/syntax/lists/profile_commands_arg1.list | 5 | ||||
-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 | 37 | ||||
-rw-r--r-- | src/firejail/landlock.c | 361 | ||||
-rw-r--r-- | src/firejail/main.c | 28 | ||||
-rw-r--r-- | src/firejail/profile.c | 41 | ||||
-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 |
18 files changed, 730 insertions, 32 deletions
@@ -200,7 +200,8 @@ avoidr (https://github.com/avoidr) | |||
200 | - fixed mpv profile | 200 | - fixed mpv profile |
201 | - various other fixes | 201 | - various other fixes |
202 | Азалия Смарагдова/ChrysoliteAzalea (https://github.com/ChrysoliteAzalea) | 202 | Азалия Смарагдова/ChrysoliteAzalea (https://github.com/ChrysoliteAzalea) |
203 | - add support for custom AppArmor profiles (--apparmor=) | 203 | - add support for custom AppArmor profiles (--apparmor=) |
204 | - add Landlock support | ||
204 | backspac (https://github.com/backspac) | 205 | backspac (https://github.com/backspac) |
205 | - firecfg fixes | 206 | - firecfg fixes |
206 | - add steam-runtime alias | 207 | - add steam-runtime alias |
diff --git a/config.mk.in b/config.mk.in index c76ca1a98..d50c7d2f5 100644 --- a/config.mk.in +++ b/config.mk.in | |||
@@ -38,6 +38,7 @@ HAVE_FIRETUNNEL=@HAVE_FIRETUNNEL@ | |||
38 | HAVE_FORCE_NONEWPRIVS=@HAVE_FORCE_NONEWPRIVS@ | 38 | HAVE_FORCE_NONEWPRIVS=@HAVE_FORCE_NONEWPRIVS@ |
39 | HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ | 39 | HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ |
40 | HAVE_IDS=@HAVE_IDS@ | 40 | HAVE_IDS=@HAVE_IDS@ |
41 | HAVE_LANDLOCK=@HAVE_LANDLOCK@ | ||
41 | HAVE_LTS=@HAVE_LTS@ | 42 | HAVE_LTS=@HAVE_LTS@ |
42 | HAVE_NETWORK=@HAVE_NETWORK@ | 43 | HAVE_NETWORK=@HAVE_NETWORK@ |
43 | HAVE_ONLY_SYSCFG_PROFILES=@HAVE_ONLY_SYSCFG_PROFILES@ | 44 | HAVE_ONLY_SYSCFG_PROFILES=@HAVE_ONLY_SYSCFG_PROFILES@ |
@@ -60,6 +61,7 @@ MANFLAGS = \ | |||
60 | $(HAVE_FORCE_NONEWPRIVS) \ | 61 | $(HAVE_FORCE_NONEWPRIVS) \ |
61 | $(HAVE_GLOBALCFG) \ | 62 | $(HAVE_GLOBALCFG) \ |
62 | $(HAVE_IDS) \ | 63 | $(HAVE_IDS) \ |
64 | $(HAVE_LANDLOCK) \ | ||
63 | $(HAVE_LTS) \ | 65 | $(HAVE_LTS) \ |
64 | $(HAVE_NETWORK) \ | 66 | $(HAVE_NETWORK) \ |
65 | $(HAVE_ONLY_SYSCFG_PROFILES) \ | 67 | $(HAVE_ONLY_SYSCFG_PROFILES) \ |
@@ -675,6 +675,7 @@ HAVE_OVERLAYFS | |||
675 | HAVE_DBUSPROXY | 675 | HAVE_DBUSPROXY |
676 | EXTRA_LDFLAGS | 676 | EXTRA_LDFLAGS |
677 | EXTRA_CFLAGS | 677 | EXTRA_CFLAGS |
678 | HAVE_LANDLOCK | ||
678 | HAVE_SELINUX | 679 | HAVE_SELINUX |
679 | AA_LIBS | 680 | AA_LIBS |
680 | AA_CFLAGS | 681 | AA_CFLAGS |
@@ -737,6 +738,7 @@ enable_sanitizer | |||
737 | enable_ids | 738 | enable_ids |
738 | enable_apparmor | 739 | enable_apparmor |
739 | enable_selinux | 740 | enable_selinux |
741 | enable_landlock | ||
740 | enable_dbusproxy | 742 | enable_dbusproxy |
741 | enable_output | 743 | enable_output |
742 | enable_usertmpfs | 744 | enable_usertmpfs |
@@ -1396,6 +1398,7 @@ Optional Features: | |||
1396 | --enable-ids enable ids | 1398 | --enable-ids enable ids |
1397 | --enable-apparmor enable apparmor | 1399 | --enable-apparmor enable apparmor |
1398 | --enable-selinux SELinux labeling support | 1400 | --enable-selinux SELinux labeling support |
1401 | --enable-landlock Landlock self-restriction support | ||
1399 | --disable-dbusproxy disable dbus proxy | 1402 | --disable-dbusproxy disable dbus proxy |
1400 | --disable-output disable --output logging | 1403 | --disable-output disable --output logging |
1401 | --disable-usertmpfs disable tmpfs as regular user | 1404 | --disable-usertmpfs disable tmpfs as regular user |
@@ -3739,6 +3742,58 @@ then : | |||
3739 | 3742 | ||
3740 | fi | 3743 | fi |
3741 | 3744 | ||
3745 | HAVE_LANDLOCK="" | ||
3746 | |||
3747 | # Check whether --enable-landlock was given. | ||
3748 | if test ${enable_landlock+y} | ||
3749 | then : | ||
3750 | enableval=$enable_landlock; | ||
3751 | fi | ||
3752 | |||
3753 | ac_header= ac_cache= | ||
3754 | for ac_item in $ac_header_c_list | ||
3755 | do | ||
3756 | if test $ac_cache; then | ||
3757 | ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" | ||
3758 | if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then | ||
3759 | printf "%s\n" "#define $ac_item 1" >> confdefs.h | ||
3760 | fi | ||
3761 | ac_header= ac_cache= | ||
3762 | elif test $ac_header; then | ||
3763 | ac_cache=$ac_item | ||
3764 | else | ||
3765 | ac_header=$ac_item | ||
3766 | fi | ||
3767 | done | ||
3768 | |||
3769 | |||
3770 | |||
3771 | |||
3772 | |||
3773 | |||
3774 | |||
3775 | |||
3776 | if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes | ||
3777 | then : | ||
3778 | |||
3779 | printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h | ||
3780 | |||
3781 | fi | ||
3782 | if test "x$enable_landlock" != "xno" | ||
3783 | then : | ||
3784 | |||
3785 | ac_fn_c_check_header_compile "$LINENO" "linux/landlock.h" "ac_cv_header_linux_landlock_h" "$ac_includes_default" | ||
3786 | if test "x$ac_cv_header_linux_landlock_h" = xyes | ||
3787 | then : | ||
3788 | HAVE_LANDLOCK="-DHAVE_LANDLOCK" | ||
3789 | else $as_nop | ||
3790 | { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: header not found: linux/landlock.h, building without Landlock support" >&5 | ||
3791 | printf "%s\n" "$as_me: WARNING: header not found: linux/landlock.h, building without Landlock support" >&2;} | ||
3792 | fi | ||
3793 | |||
3794 | |||
3795 | fi | ||
3796 | |||
3742 | 3797 | ||
3743 | 3798 | ||
3744 | 3799 | ||
@@ -4112,6 +4167,7 @@ if test "x$enable_lts" = "xyes" | |||
4112 | then : | 4167 | then : |
4113 | 4168 | ||
4114 | HAVE_LTS="-DHAVE_LTS" | 4169 | HAVE_LTS="-DHAVE_LTS" |
4170 | HAVE_LANDLOCK="" | ||
4115 | HAVE_IDS="" | 4171 | HAVE_IDS="" |
4116 | HAVE_DBUSPROXY="" | 4172 | HAVE_DBUSPROXY="" |
4117 | HAVE_OVERLAYFS="" | 4173 | HAVE_OVERLAYFS="" |
@@ -4132,35 +4188,6 @@ then : | |||
4132 | 4188 | ||
4133 | fi | 4189 | fi |
4134 | 4190 | ||
4135 | ac_header= ac_cache= | ||
4136 | for ac_item in $ac_header_c_list | ||
4137 | do | ||
4138 | if test $ac_cache; then | ||
4139 | ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" | ||
4140 | if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then | ||
4141 | printf "%s\n" "#define $ac_item 1" >> confdefs.h | ||
4142 | fi | ||
4143 | ac_header= ac_cache= | ||
4144 | elif test $ac_header; then | ||
4145 | ac_cache=$ac_item | ||
4146 | else | ||
4147 | ac_header=$ac_item | ||
4148 | fi | ||
4149 | done | ||
4150 | |||
4151 | |||
4152 | |||
4153 | |||
4154 | |||
4155 | |||
4156 | |||
4157 | |||
4158 | if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes | ||
4159 | then : | ||
4160 | |||
4161 | printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h | ||
4162 | |||
4163 | fi | ||
4164 | ac_fn_c_check_header_compile "$LINENO" "linux/seccomp.h" "ac_cv_header_linux_seccomp_h" "$ac_includes_default" | 4191 | ac_fn_c_check_header_compile "$LINENO" "linux/seccomp.h" "ac_cv_header_linux_seccomp_h" "$ac_includes_default" |
4165 | if test "x$ac_cv_header_linux_seccomp_h" = xyes | 4192 | if test "x$ac_cv_header_linux_seccomp_h" = xyes |
4166 | then : | 4193 | then : |
@@ -5360,6 +5387,7 @@ Features: | |||
5360 | firetunnel support: $HAVE_FIRETUNNEL | 5387 | firetunnel support: $HAVE_FIRETUNNEL |
5361 | global config: $HAVE_GLOBALCFG | 5388 | global config: $HAVE_GLOBALCFG |
5362 | IDS support: $HAVE_IDS | 5389 | IDS support: $HAVE_IDS |
5390 | Landlock support: $HAVE_LANDLOCK | ||
5363 | LTS: $HAVE_LTS | 5391 | LTS: $HAVE_LTS |
5364 | manpage support: $HAVE_MAN | 5392 | manpage support: $HAVE_MAN |
5365 | network: $HAVE_NETWORK | 5393 | network: $HAVE_NETWORK |
diff --git a/configure.ac b/configure.ac index 93de61b95..bd80150ed 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -81,6 +81,16 @@ AS_IF([test "x$enable_selinux" = "xyes"], [ | |||
81 | LIBS="$LIBS -lselinux" | 81 | LIBS="$LIBS -lselinux" |
82 | ]) | 82 | ]) |
83 | 83 | ||
84 | HAVE_LANDLOCK="" | ||
85 | AC_SUBST([HAVE_LANDLOCK]) | ||
86 | AC_ARG_ENABLE([landlock], | ||
87 | [AS_HELP_STRING([--enable-landlock], [Landlock self-restriction support])]) | ||
88 | AS_IF([test "x$enable_landlock" != "xno"], [ | ||
89 | AC_CHECK_HEADER([linux/landlock.h], | ||
90 | [HAVE_LANDLOCK="-DHAVE_LANDLOCK"], | ||
91 | [AC_MSG_WARN([header not found: linux/landlock.h, building without Landlock support])]) | ||
92 | ]) | ||
93 | |||
84 | AC_SUBST([EXTRA_CFLAGS]) | 94 | AC_SUBST([EXTRA_CFLAGS]) |
85 | AC_SUBST([EXTRA_LDFLAGS]) | 95 | AC_SUBST([EXTRA_LDFLAGS]) |
86 | 96 | ||
@@ -264,6 +274,7 @@ AC_ARG_ENABLE([lts], | |||
264 | [AS_HELP_STRING([--enable-lts], [enable long-term support software version (LTS)])]) | 274 | [AS_HELP_STRING([--enable-lts], [enable long-term support software version (LTS)])]) |
265 | AS_IF([test "x$enable_lts" = "xyes"], [ | 275 | AS_IF([test "x$enable_lts" = "xyes"], [ |
266 | HAVE_LTS="-DHAVE_LTS" | 276 | HAVE_LTS="-DHAVE_LTS" |
277 | HAVE_LANDLOCK="" | ||
267 | HAVE_IDS="" | 278 | HAVE_IDS="" |
268 | HAVE_DBUSPROXY="" | 279 | HAVE_DBUSPROXY="" |
269 | HAVE_OVERLAYFS="" | 280 | HAVE_OVERLAYFS="" |
@@ -324,6 +335,7 @@ Features: | |||
324 | firetunnel support: $HAVE_FIRETUNNEL | 335 | firetunnel support: $HAVE_FIRETUNNEL |
325 | global config: $HAVE_GLOBALCFG | 336 | global config: $HAVE_GLOBALCFG |
326 | IDS support: $HAVE_IDS | 337 | IDS support: $HAVE_IDS |
338 | Landlock support: $HAVE_LANDLOCK | ||
327 | LTS: $HAVE_LTS | 339 | LTS: $HAVE_LTS |
328 | manpage support: $HAVE_MAN | 340 | manpage support: $HAVE_MAN |
329 | network: $HAVE_NETWORK | 341 | network: $HAVE_NETWORK |
diff --git a/contrib/syntax/lists/profile_commands_arg0.list b/contrib/syntax/lists/profile_commands_arg0.list index e7fecef4b..4d49e96d9 100644 --- a/contrib/syntax/lists/profile_commands_arg0.list +++ b/contrib/syntax/lists/profile_commands_arg0.list | |||
@@ -12,6 +12,7 @@ keep-config-pulse | |||
12 | keep-dev-shm | 12 | keep-dev-shm |
13 | keep-shell-rc | 13 | keep-shell-rc |
14 | keep-var-tmp | 14 | keep-var-tmp |
15 | landlock | ||
15 | machine-id | 16 | machine-id |
16 | memory-deny-write-execute | 17 | memory-deny-write-execute |
17 | netfilter | 18 | netfilter |
diff --git a/contrib/syntax/lists/profile_commands_arg1.list b/contrib/syntax/lists/profile_commands_arg1.list index 5862f16ac..cce37efa0 100644 --- a/contrib/syntax/lists/profile_commands_arg1.list +++ b/contrib/syntax/lists/profile_commands_arg1.list | |||
@@ -29,6 +29,11 @@ ip6 | |||
29 | iprange | 29 | iprange |
30 | join-or-start | 30 | join-or-start |
31 | keep-fd | 31 | keep-fd |
32 | landlock.execute | ||
33 | landlock.proc | ||
34 | landlock.read | ||
35 | landlock.special | ||
36 | landlock.write | ||
32 | mac | 37 | mac |
33 | mkdir | 38 | mkdir |
34 | mkfile | 39 | mkfile |
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..5a96fcbfd 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -150,6 +150,17 @@ typedef struct profile_entry_t { | |||
150 | 150 | ||
151 | } ProfileEntry; | 151 | } ProfileEntry; |
152 | 152 | ||
153 | typedef struct landlock_entry_t { | ||
154 | struct landlock_entry_t *next; | ||
155 | #define LL_READ 0 | ||
156 | #define LL_WRITE 1 | ||
157 | #define LL_SPECIAL 2 | ||
158 | #define LL_EXEC 3 | ||
159 | #define LL_MAX 4 | ||
160 | int type; | ||
161 | char *data; | ||
162 | } LandlockEntry; | ||
163 | |||
153 | typedef struct config_t { | 164 | typedef struct config_t { |
154 | // user data | 165 | // user data |
155 | char *username; | 166 | char *username; |
@@ -159,6 +170,7 @@ typedef struct config_t { | |||
159 | // filesystem | 170 | // filesystem |
160 | ProfileEntry *profile; | 171 | ProfileEntry *profile; |
161 | ProfileEntry *profile_rebuild_etc; // blacklist files in /etc directory used by fs_rebuild_etc() | 172 | ProfileEntry *profile_rebuild_etc; // blacklist files in /etc directory used by fs_rebuild_etc() |
173 | LandlockEntry *lprofile; | ||
162 | 174 | ||
163 | #define MAX_PROFILE_IGNORE 32 | 175 | #define MAX_PROFILE_IGNORE 32 |
164 | char *profile_ignore[MAX_PROFILE_IGNORE]; | 176 | char *profile_ignore[MAX_PROFILE_IGNORE]; |
@@ -281,6 +293,9 @@ extern int arg_overlay; // overlay option | |||
281 | extern int arg_overlay_keep; // place overlay diff in a known directory | 293 | extern int arg_overlay_keep; // place overlay diff in a known directory |
282 | extern int arg_overlay_reuse; // allow the reuse of overlays | 294 | extern int arg_overlay_reuse; // allow the reuse of overlays |
283 | 295 | ||
296 | extern int arg_landlock; // add basic Landlock rules | ||
297 | extern int arg_landlock_proc; // 0 - no access; 1 -read-only; 2 - read-write | ||
298 | |||
284 | extern int arg_seccomp; // enable default seccomp filter | 299 | extern int arg_seccomp; // enable default seccomp filter |
285 | extern int arg_seccomp32; // enable default seccomp filter for 32 bit arch | 300 | extern int arg_seccomp32; // enable default seccomp filter for 32 bit arch |
286 | extern int arg_seccomp_postexec; // need postexec ld.preload library? | 301 | extern int arg_seccomp_postexec; // need postexec ld.preload library? |
@@ -950,4 +965,26 @@ void run_ids(int argc, char **argv); | |||
950 | // oom.c | 965 | // oom.c |
951 | void oom_set(const char *oom_string); | 966 | void oom_set(const char *oom_string); |
952 | 967 | ||
968 | // landlock.c | ||
969 | #ifdef HAVE_LANDLOCK | ||
970 | int ll_get_fd(void); | ||
971 | int ll_is_supported(void); | ||
972 | int ll_read(const char *allowed_path); | ||
973 | int ll_write(const char *allowed_path); | ||
974 | int ll_special(const char *allowed_path); | ||
975 | int ll_exec(const char *allowed_path); | ||
976 | int ll_basic_system(void); | ||
977 | int ll_restrict(__u32 flags); | ||
978 | void ll_add_profile(int type, const char *data); | ||
979 | #else | ||
980 | static inline int ll_get_fd(void) { return -1; } | ||
981 | static inline int ll_read(...) { return 0; } | ||
982 | static inline int ll_write(...) { return 0; } | ||
983 | static inline int ll_special(...) { return 0; } | ||
984 | static inline int ll_exec(...) { return 0; } | ||
985 | static inline int ll_basic_system(void) { return 0; } | ||
986 | static inline int ll_restrict(...) { return 0; } | ||
987 | static inline void ll_add_profile(...) { return; } | ||
988 | #endif /* HAVE_LANDLOCK */ | ||
989 | |||
953 | #endif | 990 | #endif |
diff --git a/src/firejail/landlock.c b/src/firejail/landlock.c new file mode 100644 index 000000000..27fc1d748 --- /dev/null +++ b/src/firejail/landlock.c | |||
@@ -0,0 +1,361 @@ | |||
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 | static int ll_abi = -1; | ||
32 | |||
33 | int ll_get_fd(void) { | ||
34 | return ll_ruleset_fd; | ||
35 | } | ||
36 | |||
37 | #ifndef landlock_create_ruleset | ||
38 | static inline int | ||
39 | landlock_create_ruleset(const struct landlock_ruleset_attr *const attr, | ||
40 | const size_t size, const __u32 flags) { | ||
41 | return syscall(__NR_landlock_create_ruleset, attr, size, flags); | ||
42 | } | ||
43 | #endif | ||
44 | |||
45 | #ifndef landlock_add_rule | ||
46 | static inline int | ||
47 | landlock_add_rule(const int ruleset_fd, | ||
48 | const enum landlock_rule_type rule_type, | ||
49 | const void *const rule_attr, | ||
50 | const __u32 flags) { | ||
51 | return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, | ||
52 | rule_attr, flags); | ||
53 | } | ||
54 | #endif | ||
55 | |||
56 | #ifndef landlock_restrict_self | ||
57 | static inline int | ||
58 | landlock_restrict_self(const int ruleset_fd, const __u32 flags) { | ||
59 | return syscall(__NR_landlock_restrict_self, ruleset_fd, flags); | ||
60 | } | ||
61 | #endif | ||
62 | |||
63 | int ll_is_supported(void) { | ||
64 | if (ll_abi != -1) | ||
65 | goto out; | ||
66 | |||
67 | ll_abi = landlock_create_ruleset(NULL, 0, | ||
68 | LANDLOCK_CREATE_RULESET_VERSION); | ||
69 | if (ll_abi < 1) { | ||
70 | ll_abi = 0; | ||
71 | fprintf(stderr, "Warning: Landlock is disabled or not supported: %s, " | ||
72 | "ignoring landlock commands\n", | ||
73 | strerror(errno)); | ||
74 | goto out; | ||
75 | } | ||
76 | if (arg_debug) { | ||
77 | printf("Detected Landlock ABI version %d\n", ll_abi); | ||
78 | } | ||
79 | out: | ||
80 | return ll_abi; | ||
81 | } | ||
82 | |||
83 | static int ll_create_full_ruleset() { | ||
84 | if (!ll_is_supported()) | ||
85 | return -1; | ||
86 | |||
87 | struct landlock_ruleset_attr attr; | ||
88 | attr.handled_access_fs = | ||
89 | LANDLOCK_ACCESS_FS_EXECUTE | | ||
90 | LANDLOCK_ACCESS_FS_MAKE_BLOCK | | ||
91 | LANDLOCK_ACCESS_FS_MAKE_CHAR | | ||
92 | LANDLOCK_ACCESS_FS_MAKE_DIR | | ||
93 | LANDLOCK_ACCESS_FS_MAKE_FIFO | | ||
94 | LANDLOCK_ACCESS_FS_MAKE_REG | | ||
95 | LANDLOCK_ACCESS_FS_MAKE_SOCK | | ||
96 | LANDLOCK_ACCESS_FS_MAKE_SYM | | ||
97 | LANDLOCK_ACCESS_FS_READ_DIR | | ||
98 | LANDLOCK_ACCESS_FS_READ_FILE | | ||
99 | LANDLOCK_ACCESS_FS_REMOVE_DIR | | ||
100 | LANDLOCK_ACCESS_FS_REMOVE_FILE | | ||
101 | LANDLOCK_ACCESS_FS_WRITE_FILE; | ||
102 | |||
103 | ll_ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); | ||
104 | if (ll_ruleset_fd < 0) { | ||
105 | fprintf(stderr, "Error: failed to create a Landlock ruleset: %s\n", | ||
106 | strerror(errno)); | ||
107 | } | ||
108 | return ll_ruleset_fd; | ||
109 | } | ||
110 | |||
111 | int ll_read(const char *allowed_path) { | ||
112 | if (!ll_is_supported()) | ||
113 | return 0; | ||
114 | |||
115 | if (ll_ruleset_fd == -1) | ||
116 | ll_ruleset_fd = ll_create_full_ruleset(); | ||
117 | |||
118 | int error; | ||
119 | int allowed_fd = open(allowed_path, O_PATH | O_CLOEXEC); | ||
120 | if (allowed_fd < 0) { | ||
121 | if (arg_debug) { | ||
122 | fprintf(stderr, "%s: failed to open %s: %s\n", | ||
123 | __func__, allowed_path, strerror(errno)); | ||
124 | } | ||
125 | return 0; | ||
126 | } | ||
127 | struct landlock_path_beneath_attr target; | ||
128 | target.parent_fd = allowed_fd; | ||
129 | target.allowed_access = | ||
130 | LANDLOCK_ACCESS_FS_READ_DIR | | ||
131 | LANDLOCK_ACCESS_FS_READ_FILE; | ||
132 | |||
133 | error = landlock_add_rule(ll_ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, | ||
134 | &target, 0); | ||
135 | if (error) { | ||
136 | fprintf(stderr, "Error: %s: failed to add Landlock rule for %s: %s\n", | ||
137 | __func__, allowed_path, strerror(errno)); | ||
138 | } | ||
139 | close(allowed_fd); | ||
140 | return error; | ||
141 | } | ||
142 | |||
143 | int ll_write(const char *allowed_path) { | ||
144 | if (!ll_is_supported()) | ||
145 | return 0; | ||
146 | |||
147 | if (ll_ruleset_fd == -1) | ||
148 | ll_ruleset_fd = ll_create_full_ruleset(); | ||
149 | |||
150 | int error; | ||
151 | int allowed_fd = open(allowed_path, O_PATH | O_CLOEXEC); | ||
152 | if (allowed_fd < 0) { | ||
153 | if (arg_debug) { | ||
154 | fprintf(stderr, "%s: failed to open %s: %s\n", | ||
155 | __func__, allowed_path, strerror(errno)); | ||
156 | } | ||
157 | return 0; | ||
158 | } | ||
159 | struct landlock_path_beneath_attr target; | ||
160 | target.parent_fd = allowed_fd; | ||
161 | target.allowed_access = | ||
162 | LANDLOCK_ACCESS_FS_MAKE_DIR | | ||
163 | LANDLOCK_ACCESS_FS_MAKE_REG | | ||
164 | LANDLOCK_ACCESS_FS_MAKE_SYM | | ||
165 | LANDLOCK_ACCESS_FS_REMOVE_DIR | | ||
166 | LANDLOCK_ACCESS_FS_REMOVE_FILE | | ||
167 | LANDLOCK_ACCESS_FS_WRITE_FILE; | ||
168 | |||
169 | error = landlock_add_rule(ll_ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, | ||
170 | &target, 0); | ||
171 | if (error) { | ||
172 | fprintf(stderr, "Error: %s: failed to add Landlock rule for %s: %s\n", | ||
173 | __func__, allowed_path, strerror(errno)); | ||
174 | } | ||
175 | close(allowed_fd); | ||
176 | return error; | ||
177 | } | ||
178 | |||
179 | int ll_special(const char *allowed_path) { | ||
180 | if (!ll_is_supported()) | ||
181 | return 0; | ||
182 | |||
183 | if (ll_ruleset_fd == -1) | ||
184 | ll_ruleset_fd = ll_create_full_ruleset(); | ||
185 | |||
186 | int error; | ||
187 | int allowed_fd = open(allowed_path, O_PATH | O_CLOEXEC); | ||
188 | if (allowed_fd < 0) { | ||
189 | if (arg_debug) { | ||
190 | fprintf(stderr, "%s: failed to open %s: %s\n", | ||
191 | __func__, allowed_path, strerror(errno)); | ||
192 | } | ||
193 | return 0; | ||
194 | } | ||
195 | struct landlock_path_beneath_attr target; | ||
196 | target.parent_fd = allowed_fd; | ||
197 | target.allowed_access = | ||
198 | LANDLOCK_ACCESS_FS_MAKE_BLOCK | | ||
199 | LANDLOCK_ACCESS_FS_MAKE_CHAR | | ||
200 | LANDLOCK_ACCESS_FS_MAKE_FIFO | | ||
201 | LANDLOCK_ACCESS_FS_MAKE_SOCK; | ||
202 | |||
203 | error = landlock_add_rule(ll_ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, | ||
204 | &target, 0); | ||
205 | if (error) { | ||
206 | fprintf(stderr, "Error: %s: failed to add Landlock rule for %s: %s\n", | ||
207 | __func__, allowed_path, strerror(errno)); | ||
208 | } | ||
209 | close(allowed_fd); | ||
210 | return error; | ||
211 | } | ||
212 | |||
213 | int ll_exec(const char *allowed_path) { | ||
214 | if (!ll_is_supported()) | ||
215 | return 0; | ||
216 | |||
217 | if (ll_ruleset_fd == -1) | ||
218 | ll_ruleset_fd = ll_create_full_ruleset(); | ||
219 | |||
220 | int error; | ||
221 | int allowed_fd = open(allowed_path, O_PATH | O_CLOEXEC); | ||
222 | if (allowed_fd < 0) { | ||
223 | if (arg_debug) { | ||
224 | fprintf(stderr, "%s: failed to open %s: %s\n", | ||
225 | __func__, allowed_path, strerror(errno)); | ||
226 | } | ||
227 | return 0; | ||
228 | } | ||
229 | struct landlock_path_beneath_attr target; | ||
230 | target.parent_fd = allowed_fd; | ||
231 | target.allowed_access = | ||
232 | LANDLOCK_ACCESS_FS_EXECUTE; | ||
233 | |||
234 | error = landlock_add_rule(ll_ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, | ||
235 | &target, 0); | ||
236 | if (error) { | ||
237 | fprintf(stderr, "Error: %s: failed to add Landlock rule for %s: %s\n", | ||
238 | __func__, allowed_path, strerror(errno)); | ||
239 | } | ||
240 | close(allowed_fd); | ||
241 | return error; | ||
242 | } | ||
243 | |||
244 | int ll_basic_system(void) { | ||
245 | assert(cfg.homedir); | ||
246 | |||
247 | if (!ll_is_supported()) | ||
248 | return 0; | ||
249 | |||
250 | if (ll_ruleset_fd == -1) | ||
251 | ll_ruleset_fd = ll_create_full_ruleset(); | ||
252 | |||
253 | int error; | ||
254 | char *rundir; | ||
255 | if (asprintf(&rundir, "/run/user/%d", getuid()) == -1) | ||
256 | errExit("asprintf"); | ||
257 | |||
258 | error = | ||
259 | ll_read("/") || // whole system read | ||
260 | ll_special("/") || // sockets etc. | ||
261 | |||
262 | ll_write("/tmp") || // write access | ||
263 | ll_write("/dev") || | ||
264 | ll_write("/run/shm") || | ||
265 | ll_write(cfg.homedir) || | ||
266 | ll_write(rundir) || | ||
267 | |||
268 | ll_exec("/opt") || // exec access | ||
269 | ll_exec("/bin") || | ||
270 | ll_exec("/sbin") || | ||
271 | ll_exec("/lib") || | ||
272 | ll_exec("/lib32") || | ||
273 | ll_exec("/libx32") || | ||
274 | ll_exec("/lib64") || | ||
275 | ll_exec("/usr/bin") || | ||
276 | ll_exec("/usr/sbin") || | ||
277 | ll_exec("/usr/games") || | ||
278 | ll_exec("/usr/lib") || | ||
279 | ll_exec("/usr/lib32") || | ||
280 | ll_exec("/usr/libx32") || | ||
281 | ll_exec("/usr/lib64") || | ||
282 | ll_exec("/usr/local/bin") || | ||
283 | ll_exec("/usr/local/sbin") || | ||
284 | ll_exec("/usr/local/games") || | ||
285 | ll_exec("/usr/local/lib") || | ||
286 | ll_exec("/run/firejail"); // appimage and various firejail features | ||
287 | |||
288 | if (error) { | ||
289 | fprintf(stderr, "Error: %s: failed to set --landlock rules\n", | ||
290 | __func__); | ||
291 | } | ||
292 | free(rundir); | ||
293 | return error; | ||
294 | } | ||
295 | |||
296 | int ll_restrict(__u32 flags) { | ||
297 | if (!ll_is_supported()) | ||
298 | return 0; | ||
299 | |||
300 | int (*fnc[])(const char *) = { | ||
301 | ll_read, | ||
302 | ll_write, | ||
303 | ll_special, | ||
304 | ll_exec, | ||
305 | NULL | ||
306 | }; | ||
307 | |||
308 | LandlockEntry *ptr = cfg.lprofile; | ||
309 | while (ptr) { | ||
310 | fnc[ptr->type](ptr->data); | ||
311 | ptr = ptr->next; | ||
312 | } | ||
313 | |||
314 | if (ll_ruleset_fd == -1) | ||
315 | return 0; | ||
316 | |||
317 | int error; | ||
318 | error = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | ||
319 | if (error) { | ||
320 | fprintf(stderr, "Error: %s: failed to restrict privileges: %s\n", | ||
321 | __func__, strerror(errno)); | ||
322 | goto out; | ||
323 | } | ||
324 | error = landlock_restrict_self(ll_ruleset_fd, flags); | ||
325 | if (error) { | ||
326 | fprintf(stderr, "Error: %s: failed to enforce Landlock: %s\n", | ||
327 | __func__, strerror(errno)); | ||
328 | goto out; | ||
329 | } | ||
330 | if (arg_debug) | ||
331 | printf("%s: Enforcing Landlock\n", __func__); | ||
332 | out: | ||
333 | close(ll_ruleset_fd); | ||
334 | return error; | ||
335 | } | ||
336 | |||
337 | void ll_add_profile(int type, const char *data) { | ||
338 | assert(type >= 0); | ||
339 | assert(type < LL_MAX); | ||
340 | assert(data); | ||
341 | |||
342 | if (!ll_is_supported()) | ||
343 | return; | ||
344 | |||
345 | const char *str = data; | ||
346 | while (*str == ' ' || *str == '\t') | ||
347 | str++; | ||
348 | |||
349 | LandlockEntry *ptr = malloc(sizeof(LandlockEntry)); | ||
350 | if (!ptr) | ||
351 | errExit("malloc"); | ||
352 | memset(ptr, 0, sizeof(LandlockEntry)); | ||
353 | ptr->type = type; | ||
354 | ptr->data = strdup(str); | ||
355 | if (!ptr->data) | ||
356 | errExit("strdup"); | ||
357 | ptr->next = cfg.lprofile; | ||
358 | cfg.lprofile = ptr; | ||
359 | } | ||
360 | |||
361 | #endif /* HAVE_LANDLOCK */ | ||
diff --git a/src/firejail/main.c b/src/firejail/main.c index 0327f8bda..5bcc3a0e5 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_add_profile(LL_READ, argv[i] + 16); | ||
1524 | else if (strncmp(argv[i], "--landlock.write=", 17) == 0) | ||
1525 | ll_add_profile(LL_WRITE, argv[i] + 17); | ||
1526 | else if (strncmp(argv[i], "--landlock.special=", 19) == 0) | ||
1527 | ll_add_profile(LL_SPECIAL, argv[i] + 19); | ||
1528 | else if (strncmp(argv[i], "--landlock.execute=", 19) == 0) | ||
1529 | ll_add_profile(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 0f60e9b7d..62d3c78e7 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -1073,6 +1073,44 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1073 | return 0; | 1073 | return 0; |
1074 | } | 1074 | } |
1075 | 1075 | ||
1076 | #ifdef HAVE_LANDLOCK | ||
1077 | // Landlock ruleset paths | ||
1078 | if (strcmp(ptr, "landlock") == 0) { | ||
1079 | arg_landlock = 1; | ||
1080 | return 0; | ||
1081 | } | ||
1082 | if (strncmp(ptr, "landlock.proc ", 14) == 0) { | ||
1083 | if (strncmp(ptr + 14, "no", 2) == 0) | ||
1084 | arg_landlock_proc = 0; | ||
1085 | else if (strncmp(ptr + 14, "ro", 2) == 0) | ||
1086 | arg_landlock_proc = 1; | ||
1087 | else if (strncmp(ptr + 14, "rw", 2) == 0) | ||
1088 | arg_landlock_proc = 2; | ||
1089 | else { | ||
1090 | fprintf(stderr, "Error: invalid landlock.proc value: %s\n", | ||
1091 | ptr + 14); | ||
1092 | exit(1); | ||
1093 | } | ||
1094 | return 0; | ||
1095 | } | ||
1096 | if (strncmp(ptr, "landlock.read ", 14) == 0) { | ||
1097 | ll_add_profile(LL_READ, ptr + 14); | ||
1098 | return 0; | ||
1099 | } | ||
1100 | if (strncmp(ptr, "landlock.write ", 15) == 0) { | ||
1101 | ll_add_profile(LL_WRITE, ptr + 15); | ||
1102 | return 0; | ||
1103 | } | ||
1104 | if (strncmp(ptr, "landlock.special ", 17) == 0) { | ||
1105 | ll_add_profile(LL_SPECIAL, ptr + 17); | ||
1106 | return 0; | ||
1107 | } | ||
1108 | if (strncmp(ptr, "landlock.execute ", 17) == 0) { | ||
1109 | ll_add_profile(LL_EXEC, ptr + 17); | ||
1110 | return 0; | ||
1111 | } | ||
1112 | #endif | ||
1113 | |||
1076 | // memory deny write&execute | 1114 | // memory deny write&execute |
1077 | if (strcmp(ptr, "memory-deny-write-execute") == 0) { | 1115 | if (strcmp(ptr, "memory-deny-write-execute") == 0) { |
1078 | if (checkcfg(CFG_SECCOMP)) | 1116 | if (checkcfg(CFG_SECCOMP)) |
@@ -1897,8 +1935,7 @@ void profile_read(const char *fname) { | |||
1897 | fclose(fp); | 1935 | fclose(fp); |
1898 | } | 1936 | } |
1899 | 1937 | ||
1900 | char *profile_list_normalize(char *list) | 1938 | char *profile_list_normalize(char *list) { |
1901 | { | ||
1902 | /* Remove redundant commas. | 1939 | /* Remove redundant commas. |
1903 | * | 1940 | * |
1904 | * As result is always shorter than original, | 1941 | * As result is always shorter than original, |
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]:' |