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.
This commit is contained in:
Lasse Collin 2024-02-17 23:07:35 +02:00
parent 02e3505991
commit cae9a5e0bf
3 changed files with 69 additions and 13 deletions

View 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.

View 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)

View File

@ -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