aboutsummaryrefslogtreecommitdiff
path: root/src/xz/file_io.c
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2015-03-31 22:19:34 +0300
committerLasse Collin <lasse.collin@tukaani.org>2015-03-31 22:19:34 +0300
commit1238381143a9a7ce84839c2582ccd56ff750a440 (patch)
tree83f309268f623840648babfdf2e64a7f5cce5167 /src/xz/file_io.c
parentFix bugs and otherwise improve ax_check_capsicum.m4. (diff)
downloadxz-1238381143a9a7ce84839c2582ccd56ff750a440.tar.xz
xz: Add support for sandboxing with Capsicum.
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.
Diffstat (limited to '')
-rw-r--r--src/xz/file_io.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/xz/file_io.c b/src/xz/file_io.c
index 20f512a2..308fa1d2 100644
--- a/src/xz/file_io.c
+++ b/src/xz/file_io.c
@@ -27,6 +27,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
@@ -48,6 +56,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().
@@ -139,6 +152,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
///
@@ -656,6 +732,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;
}