|
32 | 32 | #include <sys/signalfd.h> |
33 | 33 | #include <sys/capability.h> |
34 | 34 | #include <sys/prctl.h> |
| 35 | +#include <sys/syscall.h> |
35 | 36 | #include <linux/sched.h> |
36 | 37 | #include <linux/seccomp.h> |
37 | 38 | #include <linux/filter.h> |
| 39 | +#include <linux/landlock.h> |
38 | 40 |
|
39 | 41 | #include "utils.h" |
40 | 42 | #include "network.h" |
@@ -92,6 +94,7 @@ static int opt_userns_fd = -1; |
92 | 94 | static int opt_userns2_fd = -1; |
93 | 95 | static int opt_pidns_fd = -1; |
94 | 96 | static int opt_tmp_overlay_count = 0; |
| 97 | +static bool opt_scope_abs_unix_sockets = false; |
95 | 98 | static int next_perms = -1; |
96 | 99 | static size_t next_size_arg = 0; |
97 | 100 | static int next_overlay_src_count = 0; |
@@ -305,74 +308,75 @@ usage (int ecode, FILE *out) |
305 | 308 | fprintf (out, "usage: %s [OPTIONS...] [--] COMMAND [ARGS...]\n\n", argv0 ? argv0 : "bwrap"); |
306 | 309 |
|
307 | 310 | fprintf (out, |
308 | | - " --help Print this help\n" |
309 | | - " --version Print version\n" |
310 | | - " --args FD Parse NUL-separated args from FD\n" |
311 | | - " --argv0 VALUE Set argv[0] to the value VALUE before running the program\n" |
312 | | - " --level-prefix Prepend e.g. <3> to diagnostic messages\n" |
313 | | - " --unshare-all Unshare every namespace we support by default\n" |
314 | | - " --share-net Retain the network namespace (can only combine with --unshare-all)\n" |
315 | | - " --unshare-user Create new user namespace (may be automatically implied if not setuid)\n" |
316 | | - " --unshare-user-try Create new user namespace if possible else continue by skipping it\n" |
317 | | - " --unshare-ipc Create new ipc namespace\n" |
318 | | - " --unshare-pid Create new pid namespace\n" |
319 | | - " --unshare-net Create new network namespace\n" |
320 | | - " --unshare-uts Create new uts namespace\n" |
321 | | - " --unshare-cgroup Create new cgroup namespace\n" |
322 | | - " --unshare-cgroup-try Create new cgroup namespace if possible else continue by skipping it\n" |
323 | | - " --userns FD Use this user namespace (cannot combine with --unshare-user)\n" |
324 | | - " --userns2 FD After setup switch to this user namespace, only useful with --userns\n" |
325 | | - " --disable-userns Disable further use of user namespaces inside sandbox\n" |
326 | | - " --assert-userns-disabled Fail unless further use of user namespace inside sandbox is disabled\n" |
327 | | - " --pidns FD Use this pid namespace (as parent namespace if using --unshare-pid)\n" |
328 | | - " --uid UID Custom uid in the sandbox (requires --unshare-user or --userns)\n" |
329 | | - " --gid GID Custom gid in the sandbox (requires --unshare-user or --userns)\n" |
330 | | - " --hostname NAME Custom hostname in the sandbox (requires --unshare-uts)\n" |
331 | | - " --chdir DIR Change directory to DIR\n" |
332 | | - " --clearenv Unset all environment variables\n" |
333 | | - " --setenv VAR VALUE Set an environment variable\n" |
334 | | - " --unsetenv VAR Unset an environment variable\n" |
335 | | - " --lock-file DEST Take a lock on DEST while sandbox is running\n" |
336 | | - " --sync-fd FD Keep this fd open while sandbox is running\n" |
337 | | - " --bind SRC DEST Bind mount the host path SRC on DEST\n" |
338 | | - " --bind-try SRC DEST Equal to --bind but ignores non-existent SRC\n" |
339 | | - " --dev-bind SRC DEST Bind mount the host path SRC on DEST, allowing device access\n" |
340 | | - " --dev-bind-try SRC DEST Equal to --dev-bind but ignores non-existent SRC\n" |
341 | | - " --ro-bind SRC DEST Bind mount the host path SRC readonly on DEST\n" |
342 | | - " --ro-bind-try SRC DEST Equal to --ro-bind but ignores non-existent SRC\n" |
343 | | - " --bind-fd FD DEST Bind open directory or path fd on DEST\n" |
344 | | - " --ro-bind-fd FD DEST Bind open directory or path fd read-only on DEST\n" |
345 | | - " --remount-ro DEST Remount DEST as readonly; does not recursively remount\n" |
346 | | - " --overlay-src SRC Read files from SRC in the following overlay\n" |
347 | | - " --overlay RWSRC WORKDIR DEST Mount overlayfs on DEST, with RWSRC as the host path for writes and\n" |
348 | | - " WORKDIR an empty directory on the same filesystem as RWSRC\n" |
349 | | - " --tmp-overlay DEST Mount overlayfs on DEST, with writes going to an invisible tmpfs\n" |
350 | | - " --ro-overlay DEST Mount overlayfs read-only on DEST\n" |
351 | | - " --exec-label LABEL Exec label for the sandbox\n" |
352 | | - " --file-label LABEL File label for temporary sandbox content\n" |
353 | | - " --proc DEST Mount new procfs on DEST\n" |
354 | | - " --dev DEST Mount new dev on DEST\n" |
355 | | - " --tmpfs DEST Mount new tmpfs on DEST\n" |
356 | | - " --mqueue DEST Mount new mqueue on DEST\n" |
357 | | - " --dir DEST Create dir at DEST\n" |
358 | | - " --file FD DEST Copy from FD to destination DEST\n" |
359 | | - " --bind-data FD DEST Copy from FD to file which is bind-mounted on DEST\n" |
360 | | - " --ro-bind-data FD DEST Copy from FD to file which is readonly bind-mounted on DEST\n" |
361 | | - " --symlink SRC DEST Create symlink at DEST with target SRC\n" |
362 | | - " --seccomp FD Load and use seccomp rules from FD (not repeatable)\n" |
363 | | - " --add-seccomp-fd FD Load and use seccomp rules from FD (repeatable)\n" |
364 | | - " --block-fd FD Block on FD until some data to read is available\n" |
365 | | - " --userns-block-fd FD Block on FD until the user namespace is ready\n" |
366 | | - " --info-fd FD Write information about the running container to FD\n" |
367 | | - " --json-status-fd FD Write container status to FD as multiple JSON documents\n" |
368 | | - " --new-session Create a new terminal session\n" |
369 | | - " --die-with-parent Kills with SIGKILL child process (COMMAND) when bwrap or bwrap's parent dies.\n" |
370 | | - " --as-pid-1 Do not install a reaper process with PID=1\n" |
371 | | - " --cap-add CAP Add cap CAP when running as privileged user\n" |
372 | | - " --cap-drop CAP Drop cap CAP when running as privileged user\n" |
373 | | - " --perms OCTAL Set permissions of next argument (--bind-data, --file, etc.)\n" |
374 | | - " --size BYTES Set size of next argument (only for --tmpfs)\n" |
375 | | - " --chmod OCTAL PATH Change permissions of PATH (must already exist)\n" |
| 311 | + " --help Print this help\n" |
| 312 | + " --version Print version\n" |
| 313 | + " --args FD Parse NUL-separated args from FD\n" |
| 314 | + " --argv0 VALUE Set argv[0] to the value VALUE before running the program\n" |
| 315 | + " --level-prefix Prepend e.g. <3> to diagnostic messages\n" |
| 316 | + " --unshare-all Unshare every namespace we support by default\n" |
| 317 | + " --share-net Retain the network namespace (can only combine with --unshare-all)\n" |
| 318 | + " --unshare-user Create new user namespace (may be automatically implied if not setuid)\n" |
| 319 | + " --unshare-user-try Create new user namespace if possible else continue by skipping it\n" |
| 320 | + " --unshare-ipc Create new ipc namespace\n" |
| 321 | + " --unshare-pid Create new pid namespace\n" |
| 322 | + " --unshare-net Create new network namespace\n" |
| 323 | + " --unshare-uts Create new uts namespace\n" |
| 324 | + " --unshare-cgroup Create new cgroup namespace\n" |
| 325 | + " --unshare-cgroup-try Create new cgroup namespace if possible else continue by skipping it\n" |
| 326 | + " --userns FD Use this user namespace (cannot combine with --unshare-user)\n" |
| 327 | + " --userns2 FD After setup switch to this user namespace, only useful with --userns\n" |
| 328 | + " --disable-userns Disable further use of user namespaces inside sandbox\n" |
| 329 | + " --assert-userns-disabled Fail unless further use of user namespace inside sandbox is disabled\n" |
| 330 | + " --pidns FD Use this pid namespace (as parent namespace if using --unshare-pid)\n" |
| 331 | + " --uid UID Custom uid in the sandbox (requires --unshare-user or --userns)\n" |
| 332 | + " --gid GID Custom gid in the sandbox (requires --unshare-user or --userns)\n" |
| 333 | + " --hostname NAME Custom hostname in the sandbox (requires --unshare-uts)\n" |
| 334 | + " --chdir DIR Change directory to DIR\n" |
| 335 | + " --clearenv Unset all environment variables\n" |
| 336 | + " --setenv VAR VALUE Set an environment variable\n" |
| 337 | + " --unsetenv VAR Unset an environment variable\n" |
| 338 | + " --lock-file DEST Take a lock on DEST while sandbox is running\n" |
| 339 | + " --sync-fd FD Keep this fd open while sandbox is running\n" |
| 340 | + " --bind SRC DEST Bind mount the host path SRC on DEST\n" |
| 341 | + " --bind-try SRC DEST Equal to --bind but ignores non-existent SRC\n" |
| 342 | + " --dev-bind SRC DEST Bind mount the host path SRC on DEST, allowing device access\n" |
| 343 | + " --dev-bind-try SRC DEST Equal to --dev-bind but ignores non-existent SRC\n" |
| 344 | + " --ro-bind SRC DEST Bind mount the host path SRC readonly on DEST\n" |
| 345 | + " --ro-bind-try SRC DEST Equal to --ro-bind but ignores non-existent SRC\n" |
| 346 | + " --bind-fd FD DEST Bind open directory or path fd on DEST\n" |
| 347 | + " --ro-bind-fd FD DEST Bind open directory or path fd read-only on DEST\n" |
| 348 | + " --remount-ro DEST Remount DEST as readonly; does not recursively remount\n" |
| 349 | + " --overlay-src SRC Read files from SRC in the following overlay\n" |
| 350 | + " --overlay RWSRC WORKDIR DEST Mount overlayfs on DEST, with RWSRC as the host path for writes and\n" |
| 351 | + " WORKDIR an empty directory on the same filesystem as RWSRC\n" |
| 352 | + " --tmp-overlay DEST Mount overlayfs on DEST, with writes going to an invisible tmpfs\n" |
| 353 | + " --ro-overlay DEST Mount overlayfs read-only on DEST\n" |
| 354 | + " --exec-label LABEL Exec label for the sandbox\n" |
| 355 | + " --file-label LABEL File label for temporary sandbox content\n" |
| 356 | + " --proc DEST Mount new procfs on DEST\n" |
| 357 | + " --dev DEST Mount new dev on DEST\n" |
| 358 | + " --tmpfs DEST Mount new tmpfs on DEST\n" |
| 359 | + " --mqueue DEST Mount new mqueue on DEST\n" |
| 360 | + " --dir DEST Create dir at DEST\n" |
| 361 | + " --file FD DEST Copy from FD to destination DEST\n" |
| 362 | + " --bind-data FD DEST Copy from FD to file which is bind-mounted on DEST\n" |
| 363 | + " --ro-bind-data FD DEST Copy from FD to file which is readonly bind-mounted on DEST\n" |
| 364 | + " --symlink SRC DEST Create symlink at DEST with target SRC\n" |
| 365 | + " --seccomp FD Load and use seccomp rules from FD (not repeatable)\n" |
| 366 | + " --add-seccomp-fd FD Load and use seccomp rules from FD (repeatable)\n" |
| 367 | + " --block-fd FD Block on FD until some data to read is available\n" |
| 368 | + " --userns-block-fd FD Block on FD until the user namespace is ready\n" |
| 369 | + " --info-fd FD Write information about the running container to FD\n" |
| 370 | + " --json-status-fd FD Write container status to FD as multiple JSON documents\n" |
| 371 | + " --new-session Create a new terminal session\n" |
| 372 | + " --die-with-parent Kills with SIGKILL child process (COMMAND) when bwrap or bwrap's parent dies.\n" |
| 373 | + " --as-pid-1 Do not install a reaper process with PID=1\n" |
| 374 | + " --cap-add CAP Add cap CAP when running as privileged user\n" |
| 375 | + " --cap-drop CAP Drop cap CAP when running as privileged user\n" |
| 376 | + " --perms OCTAL Set permissions of next argument (--bind-data, --file, etc.)\n" |
| 377 | + " --size BYTES Set size of next argument (only for --tmpfs)\n" |
| 378 | + " --chmod OCTAL PATH Change permissions of PATH (must already exist)\n" |
| 379 | + " --scope-abstract-unix-sockets Scope access to abstract unix sockets to within in the sandbox\n" |
376 | 380 | ); |
377 | 381 | exit (ecode); |
378 | 382 | } |
@@ -2736,6 +2740,10 @@ parse_args_recurse (int *argcp, |
2736 | 2740 | argv += 2; |
2737 | 2741 | argc -= 2; |
2738 | 2742 | } |
| 2743 | + else if (strcmp (arg, "--scope-abstract-unix-sockets") == 0) |
| 2744 | + { |
| 2745 | + opt_scope_abs_unix_sockets = true; |
| 2746 | + } |
2739 | 2747 | else if (strcmp (arg, "--") == 0) |
2740 | 2748 | { |
2741 | 2749 | argv += 1; |
@@ -2867,6 +2875,24 @@ namespace_ids_write (int fd, |
2867 | 2875 | } |
2868 | 2876 | } |
2869 | 2877 |
|
| 2878 | +#ifndef landlock_create_ruleset |
| 2879 | +static inline int |
| 2880 | +landlock_create_ruleset (const struct landlock_ruleset_attr *attr, |
| 2881 | + size_t size, |
| 2882 | + uint32_t flags) |
| 2883 | +{ |
| 2884 | + return syscall (SYS_landlock_create_ruleset, attr, size, flags); |
| 2885 | +} |
| 2886 | +#endif |
| 2887 | + |
| 2888 | +#ifndef landlock_restrict_self |
| 2889 | +static inline int |
| 2890 | +landlock_restrict_self (int ruleset_fd, uint32_t flags) |
| 2891 | +{ |
| 2892 | + return syscall (SYS_landlock_restrict_self, ruleset_fd, flags); |
| 2893 | +} |
| 2894 | +#endif |
| 2895 | + |
2870 | 2896 | int |
2871 | 2897 | main (int argc, |
2872 | 2898 | char **argv) |
@@ -3491,6 +3517,23 @@ main (int argc, |
3491 | 3517 | die ("creation of new user namespaces was not disabled as requested"); |
3492 | 3518 | } |
3493 | 3519 |
|
| 3520 | + if (opt_scope_abs_unix_sockets) |
| 3521 | + { |
| 3522 | + static const struct landlock_ruleset_attr ruleset_attr = { |
| 3523 | + .scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
| 3524 | + }; |
| 3525 | + const int abi = landlock_create_ruleset (NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); |
| 3526 | + if (abi < 0) |
| 3527 | + die_with_error ("failed to check Landlock compatibility"); |
| 3528 | + if (abi < 6) |
| 3529 | + die ("supported kernel Landlock ABI too old, version 6 or above required"); |
| 3530 | + const int ruleset_fd = landlock_create_ruleset (&ruleset_attr, sizeof (ruleset_attr), 0); |
| 3531 | + if (ruleset_fd < 0) |
| 3532 | + die_with_error ("failed to create Landlock ruleset"); |
| 3533 | + if (landlock_restrict_self (ruleset_fd, 0) < 0) |
| 3534 | + die_with_error ("failed to enforce Landlock ruleset"); |
| 3535 | + } |
| 3536 | + |
3494 | 3537 | /* All privileged ops are done now, so drop caps we don't need */ |
3495 | 3538 | drop_privs (!is_privileged, true); |
3496 | 3539 |
|
|
0 commit comments