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>
This commit is contained in:
netblue30 2023-10-24 12:43:46 -04:00 committed by Kelvin M. Klann
parent 5456ec6477
commit 13b2c566df
18 changed files with 616 additions and 30 deletions

3
README
View file

@ -197,7 +197,8 @@ avoidr (https://github.com/avoidr)
- fixed mpv profile
- various other fixes
Азалия Смарагдова/ChrysoliteAzalea (https://github.com/ChrysoliteAzalea)
- add support for custom AppArmor profiles (--apparmor=)
- add support for custom AppArmor profiles (--apparmor=)
- add Landlock support
backspac (https://github.com/backspac)
- firecfg fixes
- add steam-runtime alias

View file

@ -38,6 +38,7 @@ HAVE_FIRETUNNEL=@HAVE_FIRETUNNEL@
HAVE_FORCE_NONEWPRIVS=@HAVE_FORCE_NONEWPRIVS@
HAVE_GLOBALCFG=@HAVE_GLOBALCFG@
HAVE_IDS=@HAVE_IDS@
HAVE_LANDLOCK=@HAVE_LANDLOCK@
HAVE_LTS=@HAVE_LTS@
HAVE_NETWORK=@HAVE_NETWORK@
HAVE_ONLY_SYSCFG_PROFILES=@HAVE_ONLY_SYSCFG_PROFILES@
@ -60,6 +61,7 @@ MANFLAGS = \
$(HAVE_FORCE_NONEWPRIVS) \
$(HAVE_GLOBALCFG) \
$(HAVE_IDS) \
$(HAVE_LANDLOCK) \
$(HAVE_LTS) \
$(HAVE_NETWORK) \
$(HAVE_ONLY_SYSCFG_PROFILES) \

86
configure vendored
View file

@ -675,6 +675,7 @@ HAVE_OVERLAYFS
HAVE_DBUSPROXY
EXTRA_LDFLAGS
EXTRA_CFLAGS
HAVE_LANDLOCK
HAVE_SELINUX
AA_LIBS
AA_CFLAGS
@ -737,6 +738,7 @@ enable_sanitizer
enable_ids
enable_apparmor
enable_selinux
enable_landlock
enable_dbusproxy
enable_output
enable_usertmpfs
@ -1396,6 +1398,7 @@ Optional Features:
--enable-ids enable ids
--enable-apparmor enable apparmor
--enable-selinux SELinux labeling support
--enable-landlock Landlock self-restriction support
--disable-dbusproxy disable dbus proxy
--disable-output disable --output logging
--disable-usertmpfs disable tmpfs as regular user
@ -3739,6 +3742,58 @@ then :
fi
HAVE_LANDLOCK=""
# Check whether --enable-landlock was given.
if test ${enable_landlock+y}
then :
enableval=$enable_landlock;
fi
ac_header= ac_cache=
for ac_item in $ac_header_c_list
do
if test $ac_cache; then
ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
printf "%s\n" "#define $ac_item 1" >> confdefs.h
fi
ac_header= ac_cache=
elif test $ac_header; then
ac_cache=$ac_item
else
ac_header=$ac_item
fi
done
if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes
then :
printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
fi
if test "x$enable_landlock" != "xno"
then :
ac_fn_c_check_header_compile "$LINENO" "linux/landlock.h" "ac_cv_header_linux_landlock_h" "$ac_includes_default"
if test "x$ac_cv_header_linux_landlock_h" = xyes
then :
HAVE_LANDLOCK="-DHAVE_LANDLOCK"
else $as_nop
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: header not found: linux/landlock.h, building without Landlock support" >&5
printf "%s\n" "$as_me: WARNING: header not found: linux/landlock.h, building without Landlock support" >&2;}
fi
fi
@ -4112,6 +4167,7 @@ if test "x$enable_lts" = "xyes"
then :
HAVE_LTS="-DHAVE_LTS"
HAVE_LANDLOCK=""
HAVE_IDS=""
HAVE_DBUSPROXY=""
HAVE_OVERLAYFS=""
@ -4132,35 +4188,6 @@ then :
fi
ac_header= ac_cache=
for ac_item in $ac_header_c_list
do
if test $ac_cache; then
ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
printf "%s\n" "#define $ac_item 1" >> confdefs.h
fi
ac_header= ac_cache=
elif test $ac_header; then
ac_cache=$ac_item
else
ac_header=$ac_item
fi
done
if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes
then :
printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
fi
ac_fn_c_check_header_compile "$LINENO" "linux/seccomp.h" "ac_cv_header_linux_seccomp_h" "$ac_includes_default"
if test "x$ac_cv_header_linux_seccomp_h" = xyes
then :
@ -5360,6 +5387,7 @@ Features:
firetunnel support: $HAVE_FIRETUNNEL
global config: $HAVE_GLOBALCFG
IDS support: $HAVE_IDS
Landlock support: $HAVE_LANDLOCK
LTS: $HAVE_LTS
manpage support: $HAVE_MAN
network: $HAVE_NETWORK

View file

@ -81,6 +81,16 @@ AS_IF([test "x$enable_selinux" = "xyes"], [
LIBS="$LIBS -lselinux"
])
HAVE_LANDLOCK=""
AC_SUBST([HAVE_LANDLOCK])
AC_ARG_ENABLE([landlock],
[AS_HELP_STRING([--enable-landlock], [Landlock self-restriction support])])
AS_IF([test "x$enable_landlock" != "xno"], [
AC_CHECK_HEADER([linux/landlock.h],
[HAVE_LANDLOCK="-DHAVE_LANDLOCK"],
[AC_MSG_WARN([header not found: linux/landlock.h, building without Landlock support])])
])
AC_SUBST([EXTRA_CFLAGS])
AC_SUBST([EXTRA_LDFLAGS])
@ -264,6 +274,7 @@ AC_ARG_ENABLE([lts],
[AS_HELP_STRING([--enable-lts], [enable long-term support software version (LTS)])])
AS_IF([test "x$enable_lts" = "xyes"], [
HAVE_LTS="-DHAVE_LTS"
HAVE_LANDLOCK=""
HAVE_IDS=""
HAVE_DBUSPROXY=""
HAVE_OVERLAYFS=""
@ -324,6 +335,7 @@ Features:
firetunnel support: $HAVE_FIRETUNNEL
global config: $HAVE_GLOBALCFG
IDS support: $HAVE_IDS
Landlock support: $HAVE_LANDLOCK
LTS: $HAVE_LTS
manpage support: $HAVE_MAN
network: $HAVE_NETWORK

View file

@ -12,6 +12,7 @@ keep-config-pulse
keep-dev-shm
keep-shell-rc
keep-var-tmp
landlock
machine-id
memory-deny-write-execute
netfilter

View file

@ -29,6 +29,11 @@ ip6
iprange
join-or-start
keep-fd
landlock.execute
landlock.proc
landlock.read
landlock.special
landlock.write
mac
mkdir
mkfile

View file

@ -42,6 +42,25 @@ _firejail()
_filedir -d
return 0
;;
--landlock)
return 0
;;
--landlock.read)
_filedir
return 0
;;
--landlock.write)
_filedir
return 0
;;
--landlock.special)
_filedir
return 0
;;
--landlock.execute)
_filedir
return 0
;;
--tmpfs)
_filedir
return 0

View file

@ -363,6 +363,13 @@ static const char *const compiletime_support =
"disabled"
#endif
"\n\t- Landlock support is "
#ifdef HAVE_LANDLOCK
"enabled"
#else
"disabled"
#endif
"\n\t- networking support is "
#ifdef HAVE_NETWORK
"enabled"

View file

@ -281,6 +281,9 @@ extern int arg_overlay; // overlay option
extern int arg_overlay_keep; // place overlay diff in a known directory
extern int arg_overlay_reuse; // allow the reuse of overlays
extern int arg_landlock; // add basic Landlock rules
extern int arg_landlock_proc; // 0 - no access; 1 -read-only; 2 - read-write
extern int arg_seccomp; // enable default seccomp filter
extern int arg_seccomp32; // enable default seccomp filter for 32 bit arch
extern int arg_seccomp_postexec; // need postexec ld.preload library?
@ -950,4 +953,23 @@ void run_ids(int argc, char **argv);
// oom.c
void oom_set(const char *oom_string);
// landlock.c
#ifdef HAVE_LANDLOCK
int ll_get_fd(void);
int ll_read(const char *allowed_path);
int ll_write(const char *allowed_path);
int ll_special(const char *allowed_path);
int ll_exec(const char *allowed_path);
int ll_basic_system(void);
int ll_restrict(__u32 flags);
#else
static inline int ll_get_fd(void) { return -1; }
static inline int ll_read(...) { return 0; }
static inline int ll_write(...) { return 0; }
static inline int ll_special(...) { return 0; }
static inline int ll_exec(...) { return 0; }
static inline int ll_basic_system(void) { return 0; }
static inline int ll_restrict(...) { return 0; }
#endif /* HAVE_LANDLOCK */
#endif

263
src/firejail/landlock.c Normal file
View file

@ -0,0 +1,263 @@
/*
* Copyright (C) 2014-2023 Firejail Authors
*
* This file is part of firejail project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef HAVE_LANDLOCK
#include "firejail.h"
#include <linux/landlock.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
static int ll_ruleset_fd = -1;
int ll_get_fd(void) {
return ll_ruleset_fd;
}
#ifndef landlock_create_ruleset
static inline int
landlock_create_ruleset(const struct landlock_ruleset_attr *const attr,
const size_t size, const __u32 flags) {
return syscall(__NR_landlock_create_ruleset, attr, size, flags);
}
#endif
#ifndef landlock_add_rule
static inline int
landlock_add_rule(const int ruleset_fd,
const enum landlock_rule_type rule_type,
const void *const rule_attr,
const __u32 flags) {
return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type,
rule_attr, flags);
}
#endif
#ifndef landlock_restrict_self
static inline int
landlock_restrict_self(const int ruleset_fd, const __u32 flags) {
return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
}
#endif
static int ll_create_full_ruleset() {
struct landlock_ruleset_attr attr;
attr.handled_access_fs =
LANDLOCK_ACCESS_FS_EXECUTE |
LANDLOCK_ACCESS_FS_MAKE_BLOCK |
LANDLOCK_ACCESS_FS_MAKE_CHAR |
LANDLOCK_ACCESS_FS_MAKE_DIR |
LANDLOCK_ACCESS_FS_MAKE_FIFO |
LANDLOCK_ACCESS_FS_MAKE_REG |
LANDLOCK_ACCESS_FS_MAKE_SOCK |
LANDLOCK_ACCESS_FS_MAKE_SYM |
LANDLOCK_ACCESS_FS_READ_DIR |
LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_REMOVE_DIR |
LANDLOCK_ACCESS_FS_REMOVE_FILE |
LANDLOCK_ACCESS_FS_WRITE_FILE;
ll_ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
if (ll_ruleset_fd < 0) {
fprintf(stderr, "Error: failed to create a Landlock ruleset: %s\n",
strerror(errno));
}
return ll_ruleset_fd;
}
int ll_read(const char *allowed_path) {
if (ll_ruleset_fd == -1)
ll_ruleset_fd = ll_create_full_ruleset();
int error;
int allowed_fd = open(allowed_path, O_PATH | O_CLOEXEC);
if (allowed_fd < 0) {
if (arg_debug) {
fprintf(stderr, "%s: failed to open %s: %s\n",
__func__, allowed_path, strerror(errno));
}
return 0;
}
struct landlock_path_beneath_attr target;
target.parent_fd = allowed_fd;
target.allowed_access =
LANDLOCK_ACCESS_FS_READ_DIR |
LANDLOCK_ACCESS_FS_READ_FILE;
error = landlock_add_rule(ll_ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
&target, 0);
if (error) {
fprintf(stderr, "Error: %s: failed to add Landlock rule for %s: %s\n",
__func__, allowed_path, strerror(errno));
}
close(allowed_fd);
return error;
}
int ll_write(const char *allowed_path) {
if (ll_ruleset_fd == -1)
ll_ruleset_fd = ll_create_full_ruleset();
int error;
int allowed_fd = open(allowed_path, O_PATH | O_CLOEXEC);
if (allowed_fd < 0) {
if (arg_debug) {
fprintf(stderr, "%s: failed to open %s: %s\n",
__func__, allowed_path, strerror(errno));
}
return 0;
}
struct landlock_path_beneath_attr target;
target.parent_fd = allowed_fd;
target.allowed_access =
LANDLOCK_ACCESS_FS_MAKE_DIR |
LANDLOCK_ACCESS_FS_MAKE_REG |
LANDLOCK_ACCESS_FS_MAKE_SYM |
LANDLOCK_ACCESS_FS_REMOVE_DIR |
LANDLOCK_ACCESS_FS_REMOVE_FILE |
LANDLOCK_ACCESS_FS_WRITE_FILE;
error = landlock_add_rule(ll_ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
&target, 0);
if (error) {
fprintf(stderr, "Error: %s: failed to add Landlock rule for %s: %s\n",
__func__, allowed_path, strerror(errno));
}
close(allowed_fd);
return error;
}
int ll_special(const char *allowed_path) {
if (ll_ruleset_fd == -1)
ll_ruleset_fd = ll_create_full_ruleset();
int error;
int allowed_fd = open(allowed_path, O_PATH | O_CLOEXEC);
if (allowed_fd < 0) {
if (arg_debug) {
fprintf(stderr, "%s: failed to open %s: %s\n",
__func__, allowed_path, strerror(errno));
}
return 0;
}
struct landlock_path_beneath_attr target;
target.parent_fd = allowed_fd;
target.allowed_access =
LANDLOCK_ACCESS_FS_MAKE_BLOCK |
LANDLOCK_ACCESS_FS_MAKE_CHAR |
LANDLOCK_ACCESS_FS_MAKE_FIFO |
LANDLOCK_ACCESS_FS_MAKE_SOCK;
error = landlock_add_rule(ll_ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
&target, 0);
if (error) {
fprintf(stderr, "Error: %s: failed to add Landlock rule for %s: %s\n",
__func__, allowed_path, strerror(errno));
}
close(allowed_fd);
return error;
}
int ll_exec(const char *allowed_path) {
if (ll_ruleset_fd == -1)
ll_ruleset_fd = ll_create_full_ruleset();
int error;
int allowed_fd = open(allowed_path, O_PATH | O_CLOEXEC);
if (allowed_fd < 0) {
if (arg_debug) {
fprintf(stderr, "%s: failed to open %s: %s\n",
__func__, allowed_path, strerror(errno));
}
return 0;
}
struct landlock_path_beneath_attr target;
target.parent_fd = allowed_fd;
target.allowed_access =
LANDLOCK_ACCESS_FS_EXECUTE;
error = landlock_add_rule(ll_ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
&target, 0);
if (error) {
fprintf(stderr, "Error: %s: failed to add Landlock rule for %s: %s\n",
__func__, allowed_path, strerror(errno));
}
close(allowed_fd);
return error;
}
int ll_basic_system(void) {
assert(cfg.homedir);
if (ll_ruleset_fd == -1)
ll_ruleset_fd = ll_create_full_ruleset();
int error =
ll_read("/bin/") ||
ll_read("/dev/") ||
ll_read("/etc/") ||
ll_read("/lib/") ||
ll_read("/opt/") ||
ll_read("/usr/") ||
ll_read("/var/") ||
ll_read(cfg.homedir) ||
ll_write("/dev/") ||
ll_write(cfg.homedir) ||
ll_exec("/bin/") ||
ll_exec("/lib/") ||
ll_exec("/opt/") ||
ll_exec("/usr/");
if (error) {
fprintf(stderr, "Error: %s: failed to set --landlock rules\n",
__func__);
}
return error;
}
int ll_restrict(__u32 flags) {
if (ll_ruleset_fd == -1)
return 0;
int error;
error = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
if (error) {
fprintf(stderr, "Error: %s: failed to restrict privileges: %s\n",
__func__, strerror(errno));
goto out;
}
error = landlock_restrict_self(ll_ruleset_fd, flags);
if (error) {
fprintf(stderr, "Error: %s: failed to enforce Landlock: %s\n",
__func__, strerror(errno));
goto out;
}
if (arg_debug)
printf("%s: Enforcing Landlock\n", __func__);
out:
close(ll_ruleset_fd);
return error;
}
#endif /* HAVE_LANDLOCK */

View file

@ -75,6 +75,9 @@ int arg_overlay = 0; // overlay option
int arg_overlay_keep = 0; // place overlay diff in a known directory
int arg_overlay_reuse = 0; // allow the reuse of overlays
int arg_landlock = 0; // add basic Landlock rules
int arg_landlock_proc = 2; // 0 - no access; 1 -read-only; 2 - read-write
int arg_seccomp = 0; // enable default seccomp filter
int arg_seccomp32 = 0; // enable default seccomp filter for 32 bit arch
int arg_seccomp_postexec = 0; // need postexec ld.preload library?
@ -1500,6 +1503,31 @@ int main(int argc, char **argv, char **envp) {
else
exit_err_feature("seccomp");
}
#ifdef HAVE_LANDLOCK
else if (strcmp(argv[i], "--landlock") == 0)
arg_landlock = 1;
else if (strncmp(argv[i], "--landlock.proc=", 16) == 0) {
if (strncmp(argv[i] + 16, "no", 2) == 0)
arg_landlock_proc = 0;
else if (strncmp(argv[i] + 16, "ro", 2) == 0)
arg_landlock_proc = 1;
else if (strncmp(argv[i] + 16, "rw", 2) == 0)
arg_landlock_proc = 2;
else {
fprintf(stderr, "Error: invalid landlock.proc value: %s\n",
argv[i] + 16);
exit(1);
}
}
else if (strncmp(argv[i], "--landlock.read=", 16) == 0)
ll_read(argv[i] + 16);
else if (strncmp(argv[i], "--landlock.write=", 17) == 0)
ll_write(argv[i] + 17);
else if (strncmp(argv[i], "--landlock.special=", 19) == 0)
ll_special(argv[i] + 19);
else if (strncmp(argv[i], "--landlock.execute=", 19) == 0)
ll_exec(argv[i] + 19);
#endif
else if (strcmp(argv[i], "--memory-deny-write-execute") == 0) {
if (checkcfg(CFG_SECCOMP))
arg_memory_deny_write_execute = 1;

View file

@ -1077,6 +1077,44 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
return 0;
}
#ifdef HAVE_LANDLOCK
// Landlock ruleset paths
if (strcmp(ptr, "landlock") == 0) {
arg_landlock = 1;
return 0;
}
if (strncmp(ptr, "landlock.proc ", 14) == 0) {
if (strncmp(ptr + 14, "no", 2) == 0)
arg_landlock_proc = 0;
else if (strncmp(ptr + 14, "ro", 2) == 0)
arg_landlock_proc = 1;
else if (strncmp(ptr + 14, "rw", 2) == 0)
arg_landlock_proc = 2;
else {
fprintf(stderr, "Error: invalid landlock.proc value: %s\n",
ptr + 14);
exit(1);
}
return 0;
}
if (strncmp(ptr, "landlock.read ", 14) == 0) {
ll_read(ptr + 14);
return 0;
}
if (strncmp(ptr, "landlock.write ", 15) == 0) {
ll_write(ptr + 15);
return 0;
}
if (strncmp(ptr, "landlock.special ", 17) == 0) {
ll_special(ptr + 17);
return 0;
}
if (strncmp(ptr, "landlock.execute ", 17) == 0) {
ll_exec(ptr + 17);
return 0;
}
#endif
// memory deny write&execute
if (strcmp(ptr, "memory-deny-write-execute") == 0) {
if (checkcfg(CFG_SECCOMP))

View file

@ -516,6 +516,28 @@ void start_application(int no_sandbox, int fd, char *set_sandbox_status) {
printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD"));
}
#ifdef HAVE_LANDLOCK
//****************************
// Configure Landlock
//****************************
if (arg_landlock)
ll_basic_system();
if (ll_get_fd() != -1) {
if (arg_landlock_proc >= 1)
ll_read("/proc/");
if (arg_landlock_proc == 2)
ll_write("/proc/");
}
if (ll_restrict(0)) {
// It isn't safe to continue if Landlock self-restriction was
// enabled and the "landlock_restrict_self" syscall has failed.
fprintf(stderr, "Error: ll_restrict() failed, exiting...\n");
exit(1);
}
#endif
if (just_run_the_shell) {
char *arg[2];
arg[0] = cfg.usershell;

View file

@ -133,6 +133,14 @@ static const char *const usage_str =
" --keep-fd - inherit open file descriptors to sandbox.\n"
" --keep-shell-rc - do not copy shell rc files from /etc/skel\n"
" --keep-var-tmp - /var/tmp directory is untouched.\n"
#ifdef HAVE_LANDLOCK
" --landlock - add basic rules to the Landlock ruleset.\n"
" --landlock.proc=no|ro|rw - add an access rule for /proc to the Landlock ruleset.\n"
" --landlock.read=path - add a read access rule for the path to the Landlock ruleset.\n"
" --landlock.write=path - add a write access rule for the path to the Landlock ruleset.\n"
" --landlock.special=path - add an access rule for the path to the Landlock ruleset for creating block/char devices, named pipes and sockets.\n"
" --landlock.execute=path - add an execute access rule for the path to the Landlock ruleset.\n"
#endif
" --list - list all sandboxes.\n"
#ifdef HAVE_FILE_TRANSFER
" --ls=name|pid dir_or_filename - list files in sandbox container.\n"

View file

@ -1338,6 +1338,13 @@ void close_all(int *keep_list, size_t sz) {
if (keep)
continue;
#ifdef HAVE_LANDLOCK
// Don't close the file descriptor of the Landlock ruleset; it
// will be automatically closed by the "ll_restrict" wrapper
// function.
if (fd == ll_get_fd())
continue;
#endif
close(fd);
}
closedir(dir);

View file

@ -507,6 +507,37 @@ Blacklist all Linux capabilities.
.TP
\fBcaps.keep capability,capability,capability
Whitelist given Linux capabilities.
#ifdef HAVE_LANDLOCK
.TP
\fBlandlock
Create a Landlock ruleset (if it doesn't already exist) and add basic access
rules to it.
.TP
\fBlandlock.proc no|ro|rw
Add 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.
.TP
\fBlandlock.read path
Create a Landlock ruleset (if it doesn't already exist) and add a read access
rule for path.
.TP
\fBlandlock.write path
Create a Landlock ruleset (if it doesn't already exist) and add a write access
rule for path.
.TP
\fBlandlock.special path
Create a Landlock ruleset (if it doesn't already exist) and add a rule that
allows the creation of block devices, character devices, named pipes (FIFOs)
and Unix domain sockets beneath given path.
.TP
\fBlandlock.execute path
Create a Landlock ruleset (if it doesn't already exist) and add an execution
permission rule for path.
#endif
.TP
\fBmemory-deny-write-execute
Install a seccomp filter to block attempts to create memory mappings

View file

@ -1243,6 +1243,52 @@ Example:
.br
$ firejail --keep-var-tmp
#ifdef HAVE_LANDLOCK
.TP
\fB\-\-landlock
Create a Landlock ruleset (if it doesn't already exist) and add basic access
rules to it.
The basic set of rules applies the following access permissions:
.PP
.RS
- read: /bin, /dev, /etc, /lib, /opt, /proc, /usr, /var
.br
- write: /dev, /proc
.br
- exec: /bin, /lib, /opt, /usr
.RE
.PP
See the \fBLANDLOCK\fR section for more information.
.TP
\fB\-\-landlock.proc=no|ro|rw
Add 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.
.TP
\fB\-\-landlock.read=path
Create a Landlock ruleset (if it doesn't already exist) and add a read access
rule for path.
.TP
\fB\-\-landlock.write=path
Create a Landlock ruleset (if it doesn't already exist) and add a write access
rule for path.
.TP
\fB\-\-landlock.special=path
Create a Landlock ruleset (if it doesn't already exist) and add a rule that
allows the creation of block devices, character devices, named pipes (FIFOs)
and Unix domain sockets beneath given path.
.TP
\fB\-\-landlock.execute=path
Create a Landlock ruleset (if it doesn't already exist) and add an execution
permission rule for path.
.PP
Example:
.PP
$ firejail \-\-landlock.read=/ \-\-landlock.write=/home \-\-landlock.execute=/usr
#endif
.TP
\fB\-\-list
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
$ firejail --apparmor firefox
#endif
#ifdef HAVE_LANDLOCK
.SH LANDLOCK
Landlock is a Linux security module first introduced in version 5.13 of the
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 a basic set of rules (see
\fB\-\-landlock\fR) and with a custom set of rules.
.TP
Important notes:
.PP
.RS
- 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.
.PP
- Access to the /proc directory is managed through the \fB\-\-landlock.proc\fR
command line option.
.PP
- 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.
.RE
.PP
To 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:
.PP
$ firejail \-\-landlock \-\-landlock.read=/media \-\-landlock.proc=ro mc
#endif
.SH DESKTOP INTEGRATION
A symbolic link to /usr/bin/firejail under the name of a program, will start the program in Firejail sandbox.
The symbolic link should be placed in the first $PATH position. On most systems, a good place

View file

@ -106,6 +106,11 @@ _firejail_args=(
'--keep-fd[inherit open file descriptors to sandbox]: :'
'--keep-shell-rc[do not copy shell rc files from /etc/skel]'
'--keep-var-tmp[/var/tmp directory is untouched]'
'--landlock.proc=-[add an access rule for /proc to the Landlock ruleset]: :(no ro rw)'
'--landlock.read=-[add a read access rule for the path to the Landlock ruleset]: :_files'
'--landlock.write=-[add a write access rule for the path to the Landlock ruleset]: :_files'
'--landlock.special=-[add an access rule for the path to the Landlock ruleset for creating block/char devices, named pipes and sockets]: :_files'
'--landlock.execute=-[add an execute access rule for the path to the Landlock ruleset]: :_files'
'--machine-id[spoof /etc/machine-id with a random id]'
'--memory-deny-write-execute[seccomp filter to block attempts to create memory mappings that are both writable and executable]'
'*--mkdir=-[create a directory]:'