]> git.ipfire.org Git - thirdparty/xz.git/commitdiff
xz: Use stricter pledge(2) and Landlock sandbox.
authorLasse Collin <lasse.collin@tukaani.org>
Sat, 17 Feb 2024 21:07:35 +0000 (23:07 +0200)
committerLasse Collin <lasse.collin@tukaani.org>
Sat, 17 Feb 2024 21:07:35 +0000 (23:07 +0200)
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
src/xz/sandbox.c
src/xz/sandbox.h

index c3e81467765bd21bf4a95d3b956921867b118a08..71b5ef7b7001ad028a69c88f59d2374f7f93240e 100644 (file)
@@ -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.
index 8a2c115c2a14891e17a301abcaace28b4fc7f27c..9d0df4171d830eb62da2a2a2a90f9d604ba73c8b 100644 (file)
@@ -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)
index 795c550fecd03f5ea52d71e9d32609d226d891a6..f41b4725ce3f03b473feb385ce4a463c1806d1d4 100644 (file)
 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