From cae9a5e0bf422e6c5e64180805904f7ed02dc3aa Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Sat, 17 Feb 2024 23:07:35 +0200 Subject: 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. --- src/xz/main.c | 46 +++++++++++++++++++++++++++++++++------------- src/xz/sandbox.c | 32 ++++++++++++++++++++++++++++++++ src/xz/sandbox.h | 4 ++++ 3 files changed, 69 insertions(+), 13 deletions(-) (limited to 'src/xz') 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 @@ -81,6 +81,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__)), @@ -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")); @@ -222,6 +235,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__)), @@ -254,6 +278,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 -- cgit v1.2.3