1
0
Fork 0
mirror of https://git.tukaani.org/xz.git synced 2024-04-04 12:36:23 +02:00

xz: Support basic sandboxing with Linux Landlock (ABI versions 1-3).

It is enabled only when decompressing one file to stdout,
similar to how Capsicum is used.

Landlock was added in Linux 5.13.
This commit is contained in:
Lasse Collin 2023-10-09 22:07:52 +03:00
parent 3a1e9fd031
commit 8276c7f41c
5 changed files with 98 additions and 5 deletions

View file

@ -1246,7 +1246,8 @@ if(NOT MSVC OR MSVC_VERSION GREATER_EQUAL 1900)
# OFF Disable sandboxing. # OFF Disable sandboxing.
# capsicum Require Capsicum (FreeBSD >= 10.2) and fail if not found. # capsicum Require Capsicum (FreeBSD >= 10.2) and fail if not found.
# pledge Require pledge(2) (OpenBSD >= 5.9) and fail if not found. # pledge Require pledge(2) (OpenBSD >= 5.9) and fail if not found.
set(SUPPORTED_SANDBOX_METHODS ON OFF capsicum pledge) # landlock Require Landlock (Linux >= 5.13) and fail if not found.
set(SUPPORTED_SANDBOX_METHODS ON OFF capsicum pledge landlock)
set(ENABLE_SANDBOX ON CACHE STRING "Sandboxing method to use in 'xz'") set(ENABLE_SANDBOX ON CACHE STRING "Sandboxing method to use in 'xz'")
@ -1285,6 +1286,15 @@ if(NOT MSVC OR MSVC_VERSION GREATER_EQUAL 1900)
endif() endif()
endif() endif()
# Sandboxing: Landlock
if(NOT SANDBOX_FOUND AND ENABLE_SANDBOX MATCHES "^ON$|^landlock$")
check_include_file(linux/landlock.h HAVE_LINUX_LANDLOCK_H)
if(HAVE_LINUX_LANDLOCK_H)
target_compile_definitions(xz PRIVATE HAVE_LINUX_LANDLOCK_H)
set(SANDBOX_FOUND ON)
endif()
endif()
if(NOT SANDBOX_FOUND AND NOT ENABLE_SANDBOX MATCHES "^ON$|^OFF$") if(NOT SANDBOX_FOUND AND NOT ENABLE_SANDBOX MATCHES "^ON$|^OFF$")
message(SEND_ERROR "ENABLE_SANDBOX=${ENABLE_SANDBOX} was used but " message(SEND_ERROR "ENABLE_SANDBOX=${ENABLE_SANDBOX} was used but "
"support for the sandboxing method wasn't found.") "support for the sandboxing method wasn't found.")

View file

@ -519,7 +519,7 @@ AM_CONDITIONAL([COND_DOC], [test x$enable_doc != xno])
AC_MSG_CHECKING([if sandboxing should be used]) AC_MSG_CHECKING([if sandboxing should be used])
AC_ARG_ENABLE([sandbox], [AS_HELP_STRING([--enable-sandbox=METHOD], AC_ARG_ENABLE([sandbox], [AS_HELP_STRING([--enable-sandbox=METHOD],
[Sandboxing METHOD can be [Sandboxing METHOD can be
'auto', 'no', 'capsicum', or 'pledge'. 'auto', 'no', 'capsicum', 'pledge', or 'landlock'.
The default is 'auto' which enables sandboxing if The default is 'auto' which enables sandboxing if
a supported sandboxing method is found.])], a supported sandboxing method is found.])],
[], [enable_sandbox=auto]) [], [enable_sandbox=auto])
@ -527,12 +527,12 @@ case $enable_sandbox in
auto) auto)
AC_MSG_RESULT([maybe (autodetect)]) AC_MSG_RESULT([maybe (autodetect)])
;; ;;
no | capsicum | pledge) no | capsicum | pledge | landlock)
AC_MSG_RESULT([$enable_sandbox]) AC_MSG_RESULT([$enable_sandbox])
;; ;;
*) *)
AC_MSG_RESULT([]) AC_MSG_RESULT([])
AC_MSG_ERROR([--enable-sandbox only accepts 'auto', 'no', 'capsicum', or 'pledge'.]) AC_MSG_ERROR([--enable-sandbox only accepts 'auto', 'no', 'capsicum', 'pledge', or 'landlock'.])
;; ;;
esac esac
@ -1059,6 +1059,11 @@ AS_CASE([$enable_sandbox],
AC_CHECK_FUNCS([pledge], [enable_sandbox=found]) AC_CHECK_FUNCS([pledge], [enable_sandbox=found])
] ]
) )
AS_CASE([$enable_sandbox],
[auto | landlock], [
AC_CHECK_HEADERS([linux/landlock.h], [enable_sandbox=found])
]
)
# If a specific sandboxing method was explicitly requested and it wasn't # If a specific sandboxing method was explicitly requested and it wasn't
# found, give an error. # found, give an error.

View file

@ -33,6 +33,11 @@ static bool warn_fchown;
# include <sys/capsicum.h> # include <sys/capsicum.h>
#endif #endif
#ifdef HAVE_LINUX_LANDLOCK_H
# include <linux/landlock.h>
# include <sys/syscall.h>
#endif
#include "tuklib_open_stdxxx.h" #include "tuklib_open_stdxxx.h"
#ifdef _MSC_VER #ifdef _MSC_VER
@ -253,6 +258,59 @@ io_sandbox_enter(int src_fd)
(void)src_fd; (void)src_fd;
#elif defined(HAVE_LINUX_LANDLOCK_H)
int landlock_abi = syscall(SYS_landlock_create_ruleset,
(void *)NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
if (landlock_abi > 0) {
// We support ABI versions 1-3.
if (landlock_abi > 3)
landlock_abi = 3;
// We want to set all supported flags in handled_access_fs.
// This way the ruleset will initially forbid access to all
// actions that the available Landlock ABI version supports.
// Exceptions can be added using landlock_add_rule(2) to
// allow certain actions on certain files or directories.
//
// The same flag values are used on all archs. ABI v2 and v3
// both add one new flag.
//
// First in ABI v1: LANDLOCK_ACCESS_FS_EXECUTE = 1ULL << 0
// Last in ABI v1: LANDLOCK_ACCESS_FS_MAKE_SYM = 1ULL << 12
// Last in ABI v2: LANDLOCK_ACCESS_FS_REFER = 1ULL << 13
// Last in ABI v3: LANDLOCK_ACCESS_FS_TRUNCATE = 1ULL << 14
//
// This makes it simple to set the mask based on the ABI
// version and we don't need to care which flags are #defined
// in the installed <linux/landlock.h>.
const struct landlock_ruleset_attr attr = {
.handled_access_fs = (1ULL << (12 + landlock_abi)) - 1
};
const int ruleset_fd = syscall(SYS_landlock_create_ruleset,
&attr, sizeof(attr), 0U);
if (ruleset_fd < 0)
goto error;
// All files we need should have already been openend. Thus,
// we don't need to add any rules using landlock_add_rule(2)
// before activating the sandbox.
//
// NOTE: It's possible that the hack at the beginning of this
// function isn't be good enough. It tries to get translations
// and libc-specific files loaded but if it's not good enough
// then perhaps a Landlock rule to allow reading from /usr
// and/or the xz installation prefix would be needed.
//
// prctl(PR_SET_NO_NEW_PRIVS, ...) was already called in
// main() so we don't do it here again.
if (syscall(SYS_landlock_restrict_self, ruleset_fd, 0U) != 0)
goto error;
}
(void)src_fd;
#else #else
# error ENABLE_SANDBOX is defined but no sandboxing method was found. # error ENABLE_SANDBOX is defined but no sandboxing method was found.
#endif #endif

View file

@ -13,6 +13,13 @@
#include "private.h" #include "private.h"
#include <ctype.h> #include <ctype.h>
// prctl(PR_SET_NO_NEW_PRIVS, ...) is required with Landlock but it can be
// activated even when conditions for strict sandboxing aren't met.
#ifdef HAVE_LINUX_LANDLOCK_H
# include <sys/prctl.h>
#endif
/// Exit status to use. This can be changed with set_exit_status(). /// Exit status to use. This can be changed with set_exit_status().
static enum exit_status_type exit_status = E_SUCCESS; static enum exit_status_type exit_status = E_SUCCESS;
@ -156,6 +163,18 @@ main(int argc, char **argv)
} }
#endif #endif
#ifdef HAVE_LINUX_LANDLOCK_H
// Prevent the process from gaining new privileges. This must be done
// before landlock_restrict_self(2) in file_io.c but since we will
// never need new privileges, this call can be done here already.
//
// This is supported since Linux 3.5. Ignore the return value to
// keep compatibility with old kernels. landlock_restrict_self(2)
// will fail if the no_new_privs attribute isn't set, thus if prctl()
// fails here the error will still be detected when it matters.
(void)prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
#endif
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
InitializeCriticalSection(&exit_status_cs); InitializeCriticalSection(&exit_status_cs);
#endif #endif

View file

@ -52,7 +52,8 @@
# define STDERR_FILENO (fileno(stderr)) # define STDERR_FILENO (fileno(stderr))
#endif #endif
#if defined(HAVE_CAP_RIGHTS_LIMIT) || defined(HAVE_PLEDGE) #if defined(HAVE_CAP_RIGHTS_LIMIT) || defined(HAVE_PLEDGE) \
|| defined(HAVE_LINUX_LANDLOCK_H)
# define ENABLE_SANDBOX 1 # define ENABLE_SANDBOX 1
#endif #endif