mirror of
https://git.tukaani.org/xz.git
synced 2024-04-04 12:36:23 +02:00
xz: Add support for sandboxing with Capsicum (disabled by default).
In the v5.2 branch this feature is considered experimental and thus disabled by default. The sandboxing is used conditionally as described in main.c. This isn't optimal but it was much easier to implement than a full sandboxing solution and it still covers the most common use cases where xz is writing to standard output. This should have practically no effect on performance even with small files as fork() isn't needed. C and locale libraries can open files as needed. This has been fine in the past, but it's a problem with things like Capsicum. io_sandbox_enter() tries to ensure that various locale-related files have been loaded before cap_enter() is called, but it's possible that there are other similar problems which haven't been seen yet. Currently Capsicum is available on FreeBSD 10 and later and there is a port to Linux too. Thanks to Loganaden Velvindron for help.
This commit is contained in:
parent
3ca1d5e632
commit
ce2542d220
6 changed files with 151 additions and 1 deletions
41
configure.ac
41
configure.ac
|
@ -492,6 +492,30 @@ AC_MSG_RESULT([$enable_symbol_versions])
|
|||
AM_CONDITIONAL([COND_SYMVERS], [test "x$enable_symbol_versions" = xyes])
|
||||
|
||||
|
||||
##############
|
||||
# Sandboxing #
|
||||
##############
|
||||
|
||||
AC_MSG_CHECKING([if sandboxing should be used])
|
||||
AC_ARG_ENABLE([sandbox], [AS_HELP_STRING([--enable-sandbox=METHOD],
|
||||
[This is an experimental feature.
|
||||
Sandboxing METHOD can be `auto', `no', or `capsicum'.
|
||||
The default is `no'.])],
|
||||
[], [enable_sandbox=no])
|
||||
case $enable_sandbox in
|
||||
auto)
|
||||
AC_MSG_RESULT([maybe (autodetect)])
|
||||
;;
|
||||
no | capsicum)
|
||||
AC_MSG_RESULT([$enable_sandbox])
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT([])
|
||||
AC_MSG_ERROR([--enable-sandbox only accepts `auto', `no', or `capsicum'.])
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Checks for programs.
|
||||
###############################################################################
|
||||
|
@ -721,6 +745,23 @@ AC_CHECK_DECL([_mm_movemask_epi8],
|
|||
#include <immintrin.h>
|
||||
#endif])
|
||||
|
||||
# Check for sandbox support. If one is found, set enable_sandbox=found.
|
||||
case $enable_sandbox in
|
||||
auto | capsicum)
|
||||
AX_CHECK_CAPSICUM([enable_sandbox=found], [:])
|
||||
;;
|
||||
esac
|
||||
|
||||
# If a specific sandboxing method was explicitly requested and it wasn't
|
||||
# found, give an error.
|
||||
case $enable_sandbox in
|
||||
auto | no | found)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([$enable_sandbox support not found])
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
###############################################################################
|
||||
# If using GCC, set some additional AM_CFLAGS:
|
||||
|
|
|
@ -53,7 +53,7 @@ xz_CPPFLAGS = \
|
|||
-I$(top_srcdir)/src/liblzma/api \
|
||||
-I$(top_builddir)/lib
|
||||
|
||||
xz_LDADD = $(top_builddir)/src/liblzma/liblzma.la
|
||||
xz_LDADD = $(top_builddir)/src/liblzma/liblzma.la $(CAPSICUM_LIB)
|
||||
|
||||
if COND_GNULIB
|
||||
xz_LDADD += $(top_builddir)/lib/libgnu.a
|
||||
|
|
|
@ -29,6 +29,14 @@ static bool warn_fchown;
|
|||
# include <utime.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CAPSICUM
|
||||
# ifdef HAVE_SYS_CAPSICUM_H
|
||||
# include <sys/capsicum.h>
|
||||
# else
|
||||
# include <sys/capability.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "tuklib_open_stdxxx.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
|
@ -58,6 +66,11 @@ typedef enum {
|
|||
/// If true, try to create sparse files when decompressing.
|
||||
static bool try_sparse = true;
|
||||
|
||||
#ifdef ENABLE_SANDBOX
|
||||
/// True if the conditions for sandboxing (described in main()) have been met.
|
||||
static bool sandbox_allowed = false;
|
||||
#endif
|
||||
|
||||
#ifndef TUKLIB_DOSLIKE
|
||||
/// File status flags of standard input. This is used by io_open_src()
|
||||
/// and io_close_src().
|
||||
|
@ -142,6 +155,69 @@ io_no_sparse(void)
|
|||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_SANDBOX
|
||||
extern void
|
||||
io_allow_sandbox(void)
|
||||
{
|
||||
sandbox_allowed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/// Enables operating-system-specific sandbox if it is possible.
|
||||
/// src_fd is the file descriptor of the input file.
|
||||
static void
|
||||
io_sandbox_enter(int src_fd)
|
||||
{
|
||||
if (!sandbox_allowed) {
|
||||
message(V_DEBUG, _("Sandbox is disabled due "
|
||||
"to incompatible command line arguments"));
|
||||
return;
|
||||
}
|
||||
|
||||
const char dummy_str[] = "x";
|
||||
|
||||
// Try to ensure that both libc and xz locale files have been
|
||||
// loaded when NLS is enabled.
|
||||
snprintf(NULL, 0, "%s%s", _(dummy_str), strerror(EINVAL));
|
||||
|
||||
// Try to ensure that iconv data files needed for handling multibyte
|
||||
// characters have been loaded. This is needed at least with glibc.
|
||||
tuklib_mbstr_width(dummy_str, NULL);
|
||||
|
||||
#ifdef HAVE_CAPSICUM
|
||||
// Capsicum needs FreeBSD 10.0 or later.
|
||||
cap_rights_t rights;
|
||||
|
||||
if (cap_rights_limit(src_fd, cap_rights_init(&rights,
|
||||
CAP_EVENT, CAP_FCNTL, CAP_LOOKUP, CAP_READ, CAP_SEEK)))
|
||||
goto error;
|
||||
|
||||
if (cap_rights_limit(STDOUT_FILENO, cap_rights_init(&rights,
|
||||
CAP_EVENT, CAP_FCNTL, CAP_FSTAT, CAP_LOOKUP,
|
||||
CAP_WRITE, CAP_SEEK)))
|
||||
goto error;
|
||||
|
||||
if (cap_rights_limit(user_abort_pipe[1], cap_rights_init(&rights,
|
||||
CAP_EVENT, CAP_WRITE)))
|
||||
goto error;
|
||||
|
||||
if (cap_enter())
|
||||
goto error;
|
||||
|
||||
#else
|
||||
# error ENABLE_SANDBOX is defined but no sandboxing method was found.
|
||||
#endif
|
||||
|
||||
message(V_DEBUG, _("Sandbox was successfully enabled"));
|
||||
return;
|
||||
|
||||
error:
|
||||
message(V_DEBUG, _("Failed to enable the sandbox"));
|
||||
}
|
||||
#endif // ENABLE_SANDBOX
|
||||
|
||||
|
||||
#ifndef TUKLIB_DOSLIKE
|
||||
/// \brief Waits for input or output to become available or for a signal
|
||||
///
|
||||
|
@ -675,6 +751,11 @@ io_open_src(const char *src_name)
|
|||
const bool error = io_open_src_real(&pair);
|
||||
signals_unblock();
|
||||
|
||||
#ifdef ENABLE_SANDBOX
|
||||
if (!error)
|
||||
io_sandbox_enter(pair.src_fd);
|
||||
#endif
|
||||
|
||||
return error ? NULL : &pair;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,12 @@ extern void io_write_to_user_abort_pipe(void);
|
|||
extern void io_no_sparse(void);
|
||||
|
||||
|
||||
#ifdef ENABLE_SANDBOX
|
||||
/// \brief main() calls this if conditions for sandboxing have been met.
|
||||
extern void io_allow_sandbox(void);
|
||||
#endif
|
||||
|
||||
|
||||
/// \brief Open the source file
|
||||
extern file_pair *io_open_src(const char *src_name);
|
||||
|
||||
|
|
|
@ -205,6 +205,24 @@ main(int argc, char **argv)
|
|||
if (opt_mode != MODE_LIST)
|
||||
signals_init();
|
||||
|
||||
#ifdef ENABLE_SANDBOX
|
||||
// Set a flag that sandboxing is allowed if all these are true:
|
||||
// - --files or --files0 wasn't used.
|
||||
// - There is exactly one input file or we are reading from stdin.
|
||||
// - We won't create any files: output goes to stdout or --test
|
||||
// or --list was used. Note that --test implies opt_stdout = true
|
||||
// but --list doesn't.
|
||||
//
|
||||
// This is obviously not ideal but it was easy to implement and
|
||||
// it covers the most common use cases.
|
||||
//
|
||||
// TODO: Make sandboxing work for other situations too.
|
||||
if (args.files_name == NULL && args.arg_count == 1
|
||||
&& (opt_stdout || strcmp("-", args.arg_names[0]) == 0
|
||||
|| opt_mode == MODE_LIST))
|
||||
io_allow_sandbox();
|
||||
#endif
|
||||
|
||||
// coder_run() handles compression, decompression, and testing.
|
||||
// list_file() is for --list.
|
||||
void (*run)(const char *filename) = &coder_run;
|
||||
|
|
|
@ -45,6 +45,10 @@
|
|||
# define STDERR_FILENO (fileno(stderr))
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CAPSICUM
|
||||
# define ENABLE_SANDBOX 1
|
||||
#endif
|
||||
|
||||
#include "main.h"
|
||||
#include "mytime.h"
|
||||
#include "coder.h"
|
||||
|
|
Loading…
Reference in a new issue