diff options
Diffstat (limited to 'src/xzdec')
-rw-r--r-- | src/xzdec/Makefile.am | 6 | ||||
-rw-r--r-- | src/xzdec/Makefile.in | 7 | ||||
-rw-r--r-- | src/xzdec/lzmadec_w32res.rc | 5 | ||||
-rw-r--r-- | src/xzdec/xzdec.1 | 6 | ||||
-rw-r--r-- | src/xzdec/xzdec.c | 180 | ||||
-rw-r--r-- | src/xzdec/xzdec_w32res.rc | 5 |
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 |