landlock: move commands into profile and add landlock.enforce

Changes:

* Move commands from --landlock and --landlock.proc= into
  etc/inc/landlock-common.inc
* Remove --landlock and --landlock.proc=
* Add --landlock.enforce

Instead of hard-coding the default commands (and having a separate
command just for /proc), move them into a dedicated profile to make it
easier for users to interact with the entries (view, copy, add ignore
entries, etc).

Only enforce the Landlock commands if --landlock.enforce is supplied.
This allows safely adding Landlock commands to (upstream) profiles while
keeping their enforcement opt-in.  It also makes it simpler to
effectively disable all Landlock commands, by using
`--ignore=landlock.enforce`.

Relates to #6078.
This commit is contained in:
Kelvin M. Klann 2023-11-17 19:57:29 -03:00
parent 5679d1028b
commit 760f50f78a
15 changed files with 78 additions and 145 deletions

View file

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

View file

@ -30,7 +30,6 @@ iprange
join-or-start join-or-start
keep-fd keep-fd
landlock.execute landlock.execute
landlock.proc
landlock.read landlock.read
landlock.special landlock.special
landlock.write landlock.write

View file

@ -0,0 +1,39 @@
# This file is overwritten during software install.
# Persistent customizations should go in a .local file.
include landlock-common.local
landlock.read / # whole system read
landlock.read /proc
landlock.special / # sockets etc.
# write access
landlock.write ${HOME}
landlock.write ${RUNUSER}
landlock.write /dev
landlock.write /proc
landlock.write /run/shm
landlock.write /tmp
# exec access
## misc
landlock.execute /opt
landlock.execute /run/firejail # appimage and various firejail features
## bin
landlock.execute /bin
landlock.execute /sbin
landlock.execute /usr/bin
landlock.execute /usr/sbin
landlock.execute /usr/games
landlock.execute /usr/local/bin
landlock.execute /usr/local/sbin
landlock.execute /usr/local/games
## lib
landlock.execute /lib
landlock.execute /lib32
landlock.execute /libx32
landlock.execute /lib64
landlock.execute /usr/lib
landlock.execute /usr/lib32
landlock.execute /usr/libx32
landlock.execute /usr/lib64
landlock.execute /usr/local/lib

View file

@ -22,6 +22,8 @@ include disable-programs.inc
#include whitelist-usr-share-common.inc #include whitelist-usr-share-common.inc
#include whitelist-var-common.inc #include whitelist-var-common.inc
include landlock-common.inc
#apparmor #apparmor
caps.drop all caps.drop all
#ipc-namespace #ipc-namespace

View file

@ -137,6 +137,13 @@ include globals.local
#include whitelist-usr-share-common.inc #include whitelist-usr-share-common.inc
#include whitelist-var-common.inc #include whitelist-var-common.inc
# Landlock commands
##landlock.read PATH
##landlock.write PATH
##landlock.special PATH
##landlock.execute PATH
#include landlock-common.inc
##allusers ##allusers
#apparmor #apparmor
#caps.drop all #caps.drop all

View file

@ -42,7 +42,7 @@ _firejail()
_filedir -d _filedir -d
return 0 return 0
;; ;;
--landlock) --landlock.enforce)
return 0 return 0
;; ;;
--landlock.read) --landlock.read)

View file

@ -293,8 +293,7 @@ extern int arg_overlay; // overlay option
extern int arg_overlay_keep; // place overlay diff in a known directory 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_overlay_reuse; // allow the reuse of overlays
extern int arg_landlock; // add basic Landlock rules extern int arg_landlock_enforce; // enforce the Landlock ruleset
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_seccomp; // enable default seccomp filter
extern int arg_seccomp32; // enable default seccomp filter for 32 bit arch extern int arg_seccomp32; // enable default seccomp filter for 32 bit arch
@ -973,7 +972,6 @@ int ll_read(const char *allowed_path);
int ll_write(const char *allowed_path); int ll_write(const char *allowed_path);
int ll_special(const char *allowed_path); int ll_special(const char *allowed_path);
int ll_exec(const char *allowed_path); int ll_exec(const char *allowed_path);
int ll_basic_system(void);
int ll_restrict(uint32_t flags); int ll_restrict(uint32_t flags);
void ll_add_profile(int type, const char *data); void ll_add_profile(int type, const char *data);
#endif /* HAVE_LANDLOCK */ #endif /* HAVE_LANDLOCK */

View file

@ -202,56 +202,6 @@ int ll_exec(const char *allowed_path) {
return ll_fs(allowed_path, allowed_access, __func__); return ll_fs(allowed_path, allowed_access, __func__);
} }
int ll_basic_system(void) {
if (!ll_is_supported())
return 0;
if (ll_ruleset_fd == -1)
ll_ruleset_fd = ll_create_full_ruleset();
int error =
ll_read("/") || // whole system read
ll_special("/") || // sockets etc.
// write access
ll_write("${HOME}") ||
ll_write("${RUNUSER}") ||
ll_write("/dev") ||
ll_write("/run/shm") ||
ll_write("/tmp") ||
// exec access
/// misc
ll_exec("/opt") ||
ll_exec("/run/firejail") || // appimage and various firejail features
/// bin
ll_exec("/bin") ||
ll_exec("/sbin") ||
ll_exec("/usr/bin") ||
ll_exec("/usr/sbin") ||
ll_exec("/usr/games") ||
ll_exec("/usr/local/bin") ||
ll_exec("/usr/local/sbin") ||
ll_exec("/usr/local/games") ||
/// lib
ll_exec("/lib") ||
ll_exec("/lib32") ||
ll_exec("/libx32") ||
ll_exec("/lib64") ||
ll_exec("/usr/lib") ||
ll_exec("/usr/lib32") ||
ll_exec("/usr/libx32") ||
ll_exec("/usr/lib64") ||
ll_exec("/usr/local/lib");
if (error) {
fprintf(stderr, "Error: %s: failed to set --landlock rules\n",
__func__);
}
return error;
}
int ll_restrict(uint32_t flags) { int ll_restrict(uint32_t flags) {
if (!ll_is_supported()) if (!ll_is_supported())
return 0; return 0;

View file

@ -75,8 +75,7 @@ int arg_overlay = 0; // overlay option
int arg_overlay_keep = 0; // place overlay diff in a known directory int arg_overlay_keep = 0; // place overlay diff in a known directory
int arg_overlay_reuse = 0; // allow the reuse of overlays int arg_overlay_reuse = 0; // allow the reuse of overlays
int arg_landlock = 0; // add basic Landlock rules int arg_landlock_enforce = 0; // enforce the Landlock ruleset
int arg_landlock_proc = 2; // 0 - no access; 1 -read-only; 2 - read-write
int arg_seccomp = 0; // enable default seccomp filter int arg_seccomp = 0; // enable default seccomp filter
int arg_seccomp32 = 0; // enable default seccomp filter for 32 bit arch int arg_seccomp32 = 0; // enable default seccomp filter for 32 bit arch
@ -1504,21 +1503,8 @@ int main(int argc, char **argv, char **envp) {
exit_err_feature("seccomp"); exit_err_feature("seccomp");
} }
#ifdef HAVE_LANDLOCK #ifdef HAVE_LANDLOCK
else if (strcmp(argv[i], "--landlock") == 0) else if (strncmp(argv[i], "--landlock.enforce", 18) == 0)
arg_landlock = 1; arg_landlock_enforce = 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) else if (strncmp(argv[i], "--landlock.read=", 16) == 0)
ll_add_profile(LL_READ, argv[i] + 16); ll_add_profile(LL_READ, argv[i] + 16);
else if (strncmp(argv[i], "--landlock.write=", 17) == 0) else if (strncmp(argv[i], "--landlock.write=", 17) == 0)

View file

@ -1074,25 +1074,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
} }
#ifdef HAVE_LANDLOCK #ifdef HAVE_LANDLOCK
// Landlock ruleset paths if (strncmp(ptr, "landlock.enforce", 16) == 0) {
if (strcmp(ptr, "landlock") == 0) { arg_landlock_enforce = 1;
arg_landlock = 1;
return 0; 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) { if (strncmp(ptr, "landlock.read ", 14) == 0) {
ll_add_profile(LL_READ, ptr + 14); ll_add_profile(LL_READ, ptr + 14);
return 0; return 0;

View file

@ -520,21 +520,14 @@ void start_application(int no_sandbox, int fd, char *set_sandbox_status) {
//**************************** //****************************
// Configure Landlock // Configure Landlock
//**************************** //****************************
if (arg_landlock) if (arg_landlock_enforce && ll_restrict(0)) {
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 // It isn't safe to continue if Landlock self-restriction was
// enabled and the "landlock_restrict_self" syscall has failed. // enabled and the "landlock_restrict_self" syscall has failed.
fprintf(stderr, "Error: ll_restrict() failed, exiting...\n"); fprintf(stderr, "Error: ll_restrict() failed, exiting...\n");
exit(1); exit(1);
} else {
if (arg_debug)
fprintf(stderr, "Not enforcing Landlock\n");
} }
#endif #endif

View file

@ -134,8 +134,7 @@ static const char *const usage_str =
" --keep-shell-rc - do not copy shell rc files from /etc/skel\n" " --keep-shell-rc - do not copy shell rc files from /etc/skel\n"
" --keep-var-tmp - /var/tmp directory is untouched.\n" " --keep-var-tmp - /var/tmp directory is untouched.\n"
#ifdef HAVE_LANDLOCK #ifdef HAVE_LANDLOCK
" --landlock - add basic rules to the Landlock ruleset.\n" " --landlock.enforce - enforce 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.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.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.special=path - add an access rule for the path to the Landlock ruleset for creating block/char devices, named pipes and sockets.\n"

View file

@ -509,17 +509,10 @@ Blacklist all Linux capabilities.
Whitelist given Linux capabilities. Whitelist given Linux capabilities.
#ifdef HAVE_LANDLOCK #ifdef HAVE_LANDLOCK
.TP .TP
\fBlandlock \fBlandlock.enforce
Create a Landlock ruleset (if it doesn't already exist) and add basic access Enforce the Landlock ruleset.
rules to it. .PP
.TP Without it, the other Landlock commands have no effect.
\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 .TP
\fBlandlock.read path \fBlandlock.read path
Create a Landlock ruleset (if it doesn't already exist) and add a read access Create a Landlock ruleset (if it doesn't already exist) and add a read access

View file

@ -1245,31 +1245,15 @@ $ firejail --keep-var-tmp
#ifdef HAVE_LANDLOCK #ifdef HAVE_LANDLOCK
.TP .TP
\fB\-\-landlock \fB\-\-landlock.enforce
Create a Landlock ruleset (if it doesn't already exist) and add basic access Enforce the Landlock ruleset.
rules to it.
The basic set of rules applies the following access permissions:
.PP .PP
.RS Without it, the other Landlock commands have no effect.
- read: /bin, /dev, /etc, /lib, /opt, /proc, /usr, /var
.br
- write: /dev, /proc
.br
- exec: /bin, /lib, /opt, /usr
.RE
.PP .PP
.RS .RS
See the \fBLANDLOCK\fR section for more information. See the \fBLANDLOCK\fR section for more information.
.RE .RE
.TP .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 \fB\-\-landlock.read=path
Create a Landlock ruleset (if it doesn't already exist) and add a read access Create a Landlock ruleset (if it doesn't already exist) and add a read access
rule for path. rule for path.
@ -1291,7 +1275,9 @@ permission rule for path.
.br .br
Example: Example:
.br .br
$ firejail \-\-landlock.read=/ \-\-landlock.write=/home \-\-landlock.execute=/usr $ firejail \-\-landlock.read=/ \-\-landlock.write=/home
\-\-landlock.execute=/usr \-\-landlock.enforce
.PP
#endif #endif
.TP .TP
\fB\-\-list \fB\-\-list
@ -3426,7 +3412,7 @@ Firejail supports Landlock as an additional sandboxing feature.
It can be used to ensure that a sandboxed application can only access files and It can be used to ensure that a sandboxed application can only access files and
directories that it was explicitly allowed to access. directories that it was explicitly allowed to access.
Firejail supports populating the ruleset with both a basic set of rules (see Firejail supports populating the ruleset with both a basic set of rules (see
\fB\-\-landlock\fR) and with a custom set of rules. landlock-common.inc) and with a custom set of rules.
.TP .TP
Important notes: Important notes:
.PP .PP
@ -3438,9 +3424,6 @@ Because of this, enabling the Landlock feature will also cause Firejail to
enable the "No New Privileges" restriction, regardless of the profile or the enable the "No New Privileges" restriction, regardless of the profile or the
\fB\-\-nonewprivs\fR command line option. \fB\-\-nonewprivs\fR command line option.
.PP .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. - Access to the /etc directory is automatically allowed.
To override this, use the \fB\-\-writable\-etc\fR command line option. 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 You can also use the \fB\-\-private\-etc\fR option to restrict access to the
@ -3448,13 +3431,13 @@ You can also use the \fB\-\-private\-etc\fR option to restrict access to the
.RE .RE
.PP .PP
To enable Landlock self-restriction on top of your current Firejail security To enable Landlock self-restriction on top of your current Firejail security
features, pass \fB\-\-landlock\fR flag to Firejail command line. features, pass \fB\-\-landlock.enforce\fR flag to Firejail command line.
You can also use \fB\-\-landlock.read\fR, \fB\-\-landlock.write\fR, Without it, the other Landlock commands have no effect.
\fB\-\-landlock.special\fR and \fB\-\-landlock.execute\fR options together with
\fB\-\-landlock\fR or instead of it.
Example: Example:
.PP .PP
$ firejail \-\-landlock \-\-landlock.read=/media \-\-landlock.proc=ro mc $ firejail \-\-landlock.enforce \-\-landlock.read=/media mc
.PP
To disable Landlock self-restriction, use \fB\-\-ignore=landlock.enforce\fR.
#endif #endif
.SH DESKTOP INTEGRATION .SH DESKTOP INTEGRATION
A symbolic link to /usr/bin/firejail under the name of a program, will start the program in Firejail sandbox. A symbolic link to /usr/bin/firejail under the name of a program, will start the program in Firejail sandbox.

View file

@ -107,8 +107,7 @@ _firejail_args=(
'--keep-shell-rc[do not copy shell rc files from /etc/skel]' '--keep-shell-rc[do not copy shell rc files from /etc/skel]'
'--keep-var-tmp[/var/tmp directory is untouched]' '--keep-var-tmp[/var/tmp directory is untouched]'
#ifdef HAVE_LANDLOCK #ifdef HAVE_LANDLOCK
'--landlock[add basic rules to the Landlock ruleset]' '--landlock.enforce[enforce the Landlock ruleset]'
'--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.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.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.special=-[add an access rule for the path to the Landlock ruleset for creating block/char devices, named pipes and sockets]: :_files'