aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2024-02-17 23:07:35 +0200
committerLasse Collin <lasse.collin@tukaani.org>2024-02-17 23:07:35 +0200
commitcae9a5e0bf422e6c5e64180805904f7ed02dc3aa (patch)
tree50c01bd7e95cc75e4b0578ce649afd084d431882
parentxz: Support Landlock ABI version 4. (diff)
downloadxz-cae9a5e0bf422e6c5e64180805904f7ed02dc3aa.tar.xz
xz: Use stricter pledge(2) and Landlock sandbox.
This makes these sandboxing methods stricter when no files are created or deleted. That is, it's a middle ground between the initial sandbox and the strictest single-file-to-stdout sandbox: this allows opening files for reading but output has to go to stdout.
-rw-r--r--src/xz/main.c46
-rw-r--r--src/xz/sandbox.c32
-rw-r--r--src/xz/sandbox.h4
3 files changed, 69 insertions, 13 deletions
diff --git a/src/xz/main.c b/src/xz/main.c
index c3e81467..71b5ef7b 100644
--- a/src/xz/main.c
+++ b/src/xz/main.c
@@ -223,21 +223,41 @@ main(int argc, char **argv)
signals_init();
#ifdef ENABLE_SANDBOX
- // Set a flag that strict 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.
+ // Read-only sandbox can be enabled if we won't create or delete
+ // any files:
//
- // This is obviously not ideal but it was easy to implement and
- // it covers the most common use cases.
+ // - --stdout, --test, or --list was used. Note that --test
+ // implies opt_stdout = true but --list doesn't.
//
- // 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))
- sandbox_allow_strict();
+ // - Output goes to stdout because --files or --files0 wasn't used
+ // and no arguments were given on the command line or the
+ // arguments are all "-" (indicating standard input).
+ bool to_stdout_only = opt_stdout || opt_mode == MODE_LIST;
+ if (!to_stdout_only && args.files_name == NULL) {
+ // If all of the filenames provided are "-" (more than one
+ // "-" could be specified), then we are only going to be
+ // writing to standard output. Note that if no filename args
+ // were provided, args.c puts a single "-" in arg_names[0].
+ to_stdout_only = true;
+
+ for (unsigned i = 0; i < args.arg_count; ++i) {
+ if (strcmp("-", args.arg_names[i]) != 0) {
+ to_stdout_only = false;
+ break;
+ }
+ }
+ }
+
+ if (to_stdout_only) {
+ sandbox_enable_read_only();
+
+ // Allow strict sandboxing if we are processing exactly one
+ // file to standard output. This requires that --files or
+ // --files0 wasn't specified (an unknown number of filenames
+ // could be provided that way).
+ if (args.files_name == NULL && args.arg_count == 1)
+ sandbox_allow_strict();
+ }
#endif
// coder_run() handles compression, decompression, and testing.
diff --git a/src/xz/sandbox.c b/src/xz/sandbox.c
index 8a2c115c..9d0df417 100644
--- a/src/xz/sandbox.c
+++ b/src/xz/sandbox.c
@@ -82,6 +82,18 @@ sandbox_init(void)
extern void
+sandbox_enable_read_only(void)
+{
+ // We will be opening files for reading but
+ // won't create or remove any files.
+ if (pledge("stdio rpath", ""))
+ message_fatal(_("Failed to enable the sandbox"));
+
+ return;
+}
+
+
+extern void
sandbox_enable_strict_if_allowed(int src_fd lzma_attribute((__unused__)),
int pipe_event_fd lzma_attribute((__unused__)),
int pipe_write_fd lzma_attribute((__unused__)))
@@ -89,6 +101,7 @@ sandbox_enable_strict_if_allowed(int src_fd lzma_attribute((__unused__)),
if (!prepare_for_strict_sandbox())
return;
+ // All files that need to be opened have already been opened.
if (pledge("stdio", ""))
message_fatal(_("Failed to enable the sandbox"));
@@ -223,6 +236,17 @@ sandbox_init(void)
extern void
+sandbox_enable_read_only(void)
+{
+ // We will be opening files for reading but
+ // won't create or remove any files.
+ const uint64_t required_rights = LANDLOCK_ACCESS_FS_READ_FILE;
+ enable_landlock(required_rights);
+ return;
+}
+
+
+extern void
sandbox_enable_strict_if_allowed(int src_fd lzma_attribute((__unused__)),
int pipe_event_fd lzma_attribute((__unused__)),
int pipe_write_fd lzma_attribute((__unused__)))
@@ -255,6 +279,14 @@ sandbox_init(void)
extern void
+sandbox_enable_read_only(void)
+{
+ // Nothing to do.
+ return;
+}
+
+
+extern void
sandbox_enable_strict_if_allowed(
int src_fd, int pipe_event_fd, int pipe_write_fd)
{
diff --git a/src/xz/sandbox.h b/src/xz/sandbox.h
index 795c550f..f41b4725 100644
--- a/src/xz/sandbox.h
+++ b/src/xz/sandbox.h
@@ -21,6 +21,10 @@
extern void sandbox_init(void);
+/// \brief Enable sandboxing that only allows opening files for reading
+extern void sandbox_enable_read_only(void);
+
+
/// \brief Tell sandboxing code that strict sandboxing can be used
///
/// This function only sets a flag which will be read by