diff --git a/bubblewrap.c b/bubblewrap.c index 69d319b7..991a8716 100644 --- a/bubblewrap.c +++ b/bubblewrap.c @@ -32,10 +32,15 @@ #include #include #include +#include #include #include #include +#ifdef HAVE_LANDLOCK_H +#include +#endif + #include "utils.h" #include "network.h" #include "bind-mount.h" @@ -92,6 +97,8 @@ static int opt_userns_fd = -1; static int opt_userns2_fd = -1; static int opt_pidns_fd = -1; static int opt_tmp_overlay_count = 0; +static bool opt_scope_abstract_unix_sockets = false; +static bool opt_scope_abstract_unix_sockets_try = false; static int next_perms = -1; static size_t next_size_arg = 0; static int next_overlay_src_count = 0; @@ -373,6 +380,8 @@ usage (int ecode, FILE *out) " --perms OCTAL Set permissions of next argument (--bind-data, --file, etc.)\n" " --size BYTES Set size of next argument (only for --tmpfs)\n" " --chmod OCTAL PATH Change permissions of PATH (must already exist)\n" + " --scope-abstract-af-unix Prevent connecting to abstract unix sockets outside the sandbox\n" + " --scope-abstract-af-unix-try Try --scope-abstract-af-unix if possible else continue by skipping it\n" ); exit (ecode); } @@ -2736,6 +2745,14 @@ parse_args_recurse (int *argcp, argv += 2; argc -= 2; } + else if (strcmp (arg, "--scope-abstract-af-unix") == 0) + { + opt_scope_abstract_unix_sockets = true; + } + else if (strcmp (arg, "--scope-abstract-af-unix-try") == 0) + { + opt_scope_abstract_unix_sockets_try = true; + } else if (strcmp (arg, "--") == 0) { argv += 1; @@ -2867,6 +2884,26 @@ namespace_ids_write (int fd, } } +#ifdef HAVE_LANDLOCK_H +#ifndef landlock_create_ruleset +static inline int +landlock_create_ruleset (const struct landlock_ruleset_attr *attr, + size_t size, + uint32_t flags) +{ + return syscall (SYS_landlock_create_ruleset, attr, size, flags); +} +#endif + +#ifndef landlock_restrict_self +static inline int +landlock_restrict_self (int ruleset_fd, uint32_t flags) +{ + return syscall (SYS_landlock_restrict_self, ruleset_fd, flags); +} +#endif +#endif + int main (int argc, char **argv) @@ -3498,6 +3535,43 @@ main (int argc, die ("creation of new user namespaces was not disabled as requested"); } + if (opt_scope_abstract_unix_sockets) + { + #ifdef HAVE_LANDLOCK_H + static const struct landlock_ruleset_attr ruleset_attr = { + .scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET + }; + const int abi = landlock_create_ruleset (NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); + if (abi < 0) + die_with_error ("failed to check Landlock compatibility"); + if (abi < 6) + die ("supported kernel Landlock ABI too old, version 6 or above required"); + const int ruleset_fd = landlock_create_ruleset (&ruleset_attr, sizeof (ruleset_attr), 0); + if (ruleset_fd < 0) + die_with_error ("failed to create Landlock ruleset"); + if (landlock_restrict_self (ruleset_fd, 0) < 0) + die_with_error ("failed to enforce Landlock ruleset"); + #else + die ("Landlock not available at compile time, cannot implement --scope-abstract-af-unix"); + #endif + } + + #ifdef HAVE_LANDLOCK_H + if (opt_scope_abstract_unix_sockets_try) + { + static const struct landlock_ruleset_attr ruleset_attr = { + .scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET + }; + const int abi = landlock_create_ruleset (NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); + if (abi < 6) + { + const int ruleset_fd = landlock_create_ruleset (&ruleset_attr, sizeof (ruleset_attr), 0); + if (ruleset_fd < 0) + landlock_restrict_self (ruleset_fd, 0); + } + } + #endif + /* All privileged ops are done now, so drop caps we don't need */ drop_privs (!is_privileged, true); diff --git a/bwrap.xml b/bwrap.xml index f379f0fa..d2129ee7 100644 --- a/bwrap.xml +++ b/bwrap.xml @@ -617,6 +617,27 @@ command line. Please be careful to the order they are specified. + + + + Scope access to abstract unix7 sockets. + + This option will prevent the newly created sandbox from connecting to abstract AF_UNIX sockets + created outside the sandbox, + for example the X11 socket @/tmp/.X11-unix/X0, + even if the network namespace is the same. + + This has the same behaviour as LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET: see + landlock7 for details. + + + + + + Try to do the same as , + but if that isn't possible, continue without that restriction. + + diff --git a/completions/bash/bwrap b/completions/bash/bwrap index e7a523c2..aa0b7b54 100644 --- a/completions/bash/bwrap +++ b/completions/bash/bwrap @@ -15,6 +15,8 @@ _bwrap() { --disable-userns --help --new-session + --scope-abstract-af-unix + --scope-abstract-af-unix-try --unshare-all --unshare-cgroup --unshare-cgroup-try diff --git a/completions/zsh/_bwrap b/completions/zsh/_bwrap index fbddda43..15c66f0f 100644 --- a/completions/zsh/_bwrap +++ b/completions/zsh/_bwrap @@ -60,6 +60,8 @@ _bwrap_args=( '--remount-ro[Remount DEST as readonly; does not recursively remount]:mount point to remount read-only:_files' '--ro-bind-try[Equal to --ro-bind but ignores non-existent SRC]:source:_files:destination:_files' '--ro-bind[Bind mount the host path SRC readonly on DEST]:source:_files:destination:_files' + '--scope-abstract-af-unix[Prevent connecting to abstract unix sockets outside the sandbox]' + '--scope-abstract-af-unix-try[Try --scope-abstract-af-unix if possible else continue by skipping it]' '--seccomp[Load and use seccomp rules from FD]: :_guard "[0-9]#" "file descriptor to read seccomp rules from"' '--setenv[Set an environment variable]:variable to set:_parameters -g "*export*":value of variable: :' '--size[Set size in bytes for next action argument]: :->after_size' diff --git a/meson.build b/meson.build index 78678d09..3f767243 100644 --- a/meson.build +++ b/meson.build @@ -57,6 +57,10 @@ if ( ], language : 'c') endif +if cc.check_header('linux/landlock.h') + add_project_arguments('-DHAVE_LANDLOCK_H', language : 'c') +endif + bash = find_program('bash', required : false) if get_option('python') == ''