summaryrefslogtreecommitdiffstats
path: root/src/xzdec
diff options
context:
space:
mode:
Diffstat (limited to 'src/xzdec')
-rw-r--r--src/xzdec/Makefile.am6
-rw-r--r--src/xzdec/Makefile.in7
-rw-r--r--src/xzdec/lzmadec_w32res.rc5
-rw-r--r--src/xzdec/xzdec.16
-rw-r--r--src/xzdec/xzdec.c180
-rw-r--r--src/xzdec/xzdec_w32res.rc5
6 files changed, 180 insertions, 29 deletions
diff --git a/src/xzdec/Makefile.am b/src/xzdec/Makefile.am
index 90f1e92..31a6508 100644
--- a/src/xzdec/Makefile.am
+++ b/src/xzdec/Makefile.am
@@ -1,9 +1,5 @@
-##
+## SPDX-License-Identifier: 0BSD
## Author: Lasse Collin
-##
-## This file has been put into the public domain.
-## You can do whatever you want with this file.
-##
# Windows resource compiler support. It's fine to use xz_CPPFLAGS
# also for lzmadec.
diff --git a/src/xzdec/Makefile.in b/src/xzdec/Makefile.in
index b05cff1..7d44f9b 100644
--- a/src/xzdec/Makefile.in
+++ b/src/xzdec/Makefile.in
@@ -103,8 +103,8 @@ bin_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
@COND_LZMADEC_TRUE@@COND_XZDEC_TRUE@am__append_6 = lzmadec
subdir = src/xzdec
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_capsicum.m4 \
- $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/getopt.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/m4/build-to-host.m4 $(top_srcdir)/m4/getopt.m4 \
$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/host-cpu-c-abi.m4 \
$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
@@ -264,7 +264,6 @@ AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
-CAPSICUM_LIB = @CAPSICUM_LIB@
CC = @CC@
CCAS = @CCAS@
CCASDEPMODE = @CCASDEPMODE@
@@ -393,6 +392,8 @@ install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
+localedir_c = @localedir_c@
+localedir_c_make = @localedir_c_make@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
diff --git a/src/xzdec/lzmadec_w32res.rc b/src/xzdec/lzmadec_w32res.rc
index b85962d..b4b89b1 100644
--- a/src/xzdec/lzmadec_w32res.rc
+++ b/src/xzdec/lzmadec_w32res.rc
@@ -1,8 +1,7 @@
+/* SPDX-License-Identifier: 0BSD */
+
/*
* Author: Lasse Collin
- *
- * This file has been put into the public domain.
- * You can do whatever you want with this file.
*/
#define MY_TYPE VFT_APP
diff --git a/src/xzdec/xzdec.1 b/src/xzdec/xzdec.1
index 78bc9b4..5198efb 100644
--- a/src/xzdec/xzdec.1
+++ b/src/xzdec/xzdec.1
@@ -1,10 +1,8 @@
+.\" SPDX-License-Identifier: 0BSD
.\"
.\" Author: Lasse Collin
.\"
-.\" This file has been put into the public domain.
-.\" You can do whatever you want with this file.
-.\"
-.TH XZDEC 1 "2017-04-19" "Tukaani" "XZ Utils"
+.TH XZDEC 1 "2024-04-08" "Tukaani" "XZ Utils"
.SH NAME
xzdec, lzmadec \- Small .xz and .lzma decompressors
.SH SYNOPSIS
diff --git a/src/xzdec/xzdec.c b/src/xzdec/xzdec.c
index 556c548..4d88174 100644
--- a/src/xzdec/xzdec.c
+++ b/src/xzdec/xzdec.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: 0BSD
+
///////////////////////////////////////////////////////////////////////////////
//
/// \file xzdec.c
@@ -5,9 +7,6 @@
//
// Author: Lasse Collin
//
-// This file has been put into the public domain.
-// You can do whatever you want with this file.
-//
///////////////////////////////////////////////////////////////////////////////
#include "sysdefs.h"
@@ -16,7 +15,30 @@
#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
-#include <unistd.h>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_CAP_RIGHTS_LIMIT
+# include <sys/capsicum.h>
+#endif
+
+#ifdef HAVE_LINUX_LANDLOCK
+# include <linux/landlock.h>
+# include <sys/prctl.h>
+# include <sys/syscall.h>
+# ifdef LANDLOCK_ACCESS_NET_BIND_TCP
+# define LANDLOCK_ABI_MAX 4
+# else
+# define LANDLOCK_ABI_MAX 3
+# endif
+#endif
+
+#if defined(HAVE_CAP_RIGHTS_LIMIT) || defined(HAVE_PLEDGE) \
+ || defined(HAVE_LINUX_LANDLOCK)
+# define ENABLE_SANDBOX 1
+#endif
#include "getopt.h"
#include "tuklib_progname.h"
@@ -25,6 +47,10 @@
#ifdef TUKLIB_DOSLIKE
# include <fcntl.h>
# include <io.h>
+# ifdef _MSC_VER
+# define fileno _fileno
+# define setmode _setmode
+# endif
#endif
@@ -273,9 +299,123 @@ uncompress(lzma_stream *strm, FILE *file, const char *filename)
}
+#ifdef ENABLE_SANDBOX
+static void
+sandbox_enter(int src_fd)
+{
+#if defined(HAVE_CAP_RIGHTS_LIMIT)
+ // Capsicum needs FreeBSD 10.2 or later.
+ cap_rights_t rights;
+
+ if (cap_enter())
+ goto error;
+
+ if (cap_rights_limit(src_fd, cap_rights_init(&rights, CAP_READ)))
+ goto error;
+
+ // If not reading from stdin, remove all capabilities from it.
+ if (src_fd != STDIN_FILENO && cap_rights_limit(
+ STDIN_FILENO, cap_rights_clear(&rights)))
+ goto error;
+
+ if (cap_rights_limit(STDOUT_FILENO, cap_rights_init(&rights,
+ CAP_WRITE)))
+ goto error;
+
+ if (cap_rights_limit(STDERR_FILENO, cap_rights_init(&rights,
+ CAP_WRITE)))
+ goto error;
+
+#elif defined(HAVE_PLEDGE)
+ // pledge() was introduced in OpenBSD 5.9.
+ if (pledge("stdio", ""))
+ goto error;
+
+ (void)src_fd;
+
+#elif defined(HAVE_LINUX_LANDLOCK)
+ int landlock_abi = syscall(SYS_landlock_create_ruleset,
+ (void *)NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
+
+ if (landlock_abi > 0) {
+ if (landlock_abi > LANDLOCK_ABI_MAX)
+ landlock_abi = LANDLOCK_ABI_MAX;
+
+ const struct landlock_ruleset_attr attr = {
+ .handled_access_fs = (1ULL
+ << (12 + my_min(3, landlock_abi))) - 1,
+# if LANDLOCK_ABI_MAX >= 4
+ .handled_access_net = landlock_abi < 4 ? 0 :
+ (LANDLOCK_ACCESS_NET_BIND_TCP
+ | LANDLOCK_ACCESS_NET_CONNECT_TCP),
+# endif
+ };
+
+ 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 opened. Thus,
+ // we don't need to add any rules using landlock_add_rule(2)
+ // before activating the sandbox.
+ if (syscall(SYS_landlock_restrict_self, ruleset_fd, 0U) != 0)
+ goto error;
+ }
+
+ (void)src_fd;
+
+#else
+# error ENABLE_SANDBOX is defined but no sandboxing method was found.
+#endif
+
+ return;
+
+error:
+#ifdef HAVE_CAP_RIGHTS_LIMIT
+ // If a kernel is configured without capability mode support or
+ // used in an emulator that does not implement the capability
+ // system calls, then the Capsicum system calls will fail and set
+ // errno to ENOSYS. In that case xzdec will silently run without
+ // the sandbox.
+ if (errno == ENOSYS)
+ return;
+#endif
+
+ my_errorf("Failed to enable the sandbox");
+ exit(EXIT_FAILURE);
+}
+#endif
+
+
int
main(int argc, char **argv)
{
+#ifdef HAVE_PLEDGE
+ // OpenBSD's pledge(2) sandbox.
+ // Initially enable the sandbox slightly more relaxed so that
+ // the process can still open files. This allows the sandbox to
+ // be enabled when parsing command line arguments and decompressing
+ // all files (the more strict sandbox only restricts the last file
+ // that is decompressed).
+ if (pledge("stdio rpath", "")) {
+ my_errorf("Failed to enable the sandbox");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+#ifdef HAVE_LINUX_LANDLOCK
+ // Prevent the process from gaining new privileges. This must be done
+ // before landlock_restrict_self(2) 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
+
// Initialize progname which we will be used in error messages.
tuklib_progname_init(argv);
@@ -295,24 +435,42 @@ main(int argc, char **argv)
if (optind == argc) {
// No filenames given, decode from stdin.
+#ifdef ENABLE_SANDBOX
+ sandbox_enter(STDIN_FILENO);
+#endif
uncompress(&strm, stdin, "(stdin)");
} else {
// Loop through the filenames given on the command line.
do {
+ FILE *src_file;
+ const char *src_name;
+
// "-" indicates stdin.
if (strcmp(argv[optind], "-") == 0) {
- uncompress(&strm, stdin, "(stdin)");
+ src_file = stdin;
+ src_name = "(stdin)";
} else {
- FILE *file = fopen(argv[optind], "rb");
- if (file == NULL) {
- my_errorf("%s: %s", argv[optind],
+ src_name = argv[optind];
+ src_file = fopen(src_name, "rb");
+ if (src_file == NULL) {
+ my_errorf("%s: %s", src_name,
strerror(errno));
exit(EXIT_FAILURE);
}
-
- uncompress(&strm, file, argv[optind]);
- fclose(file);
}
+#ifdef ENABLE_SANDBOX
+ // Enable the strict sandbox for the last file.
+ // Then the process can no longer open additional
+ // files. The typical xzdec use case is to decompress
+ // a single file so this way the strictest sandboxing
+ // is used in most cases.
+ if (optind == argc - 1)
+ sandbox_enter(fileno(src_file));
+#endif
+ uncompress(&strm, src_file, src_name);
+
+ if (src_file != stdin)
+ (void)fclose(src_file);
} while (++optind < argc);
}
diff --git a/src/xzdec/xzdec_w32res.rc b/src/xzdec/xzdec_w32res.rc
index 0e26a22..fdbb102 100644
--- a/src/xzdec/xzdec_w32res.rc
+++ b/src/xzdec/xzdec_w32res.rc
@@ -1,8 +1,7 @@
+/* SPDX-License-Identifier: 0BSD */
+
/*
* Author: Lasse Collin
- *
- * This file has been put into the public domain.
- * You can do whatever you want with this file.
*/
#define MY_TYPE VFT_APP