From ca166d47b6b07ea0e7f9eb46b0749d5561e04878 Mon Sep 17 00:00:00 2001 From: Axel Burri Date: Sat, 6 Nov 2021 16:10:26 +0100 Subject: [PATCH] btrbk: add safe_commands config option For the paranoid. For convenience, filename checking was removed in [1], and quoting was (hopefully) implemented correctly in [2]. Allowing special characters as well as UTF8 leave behind a bad feeling, as there are many special cases that needs to be taken care of (e.g. newlines in file names, right-to-left encoding, etc.). In order to mitigate attacks expoiting these error classes, leave an option to power users which do only allow "sane" characters in their filename hierarchy. [1] 6a29b08f00 btrbk: remove filename restrictions [2] acc7f9fc83 btrbk: quote unsafe characters in shell commands --- btrbk | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/btrbk b/btrbk index fd785fb..7304006 100755 --- a/btrbk +++ b/btrbk @@ -64,6 +64,7 @@ my $host_name_match = qr/(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)* my $uuid_match = qr/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/; my $btrbk_timestamp_match = qr/(?[0-9]{4})(?[0-9]{2})(?
[0-9]{2})(T(?[0-9]{2})(?[0-9]{2})((?[0-9]{2})(?(Z|[+-][0-9]{4})))?)?(_(?[0-9]+))?/; # matches "YYYYMMDD[Thhmm[ss+0000]][_NN]" my $raw_postfix_match = qr/\.btrfs(\.($compress_format_alt))?(\.(gpg|encrypted))?/; # matches ".btrfs[.gz|bz2|xz][.gpg|encrypted]" +my $safe_file_match = qr/[0-9a-zA-Z_@\+\-\.\/]+/; # note: ubuntu uses '@' in the subvolume layout: my $group_match = qr/[a-zA-Z0-9_:-]+/; my $ssh_cipher_match = qr/[a-z0-9][a-z0-9@.-]+/; @@ -143,6 +144,7 @@ my %config_options = ( compat => { default => undef, accept => [ "no", "busybox" ] }, compat_local => { default => undef, accept => [ "no", "busybox" ] }, compat_remote => { default => undef, accept => [ "no", "busybox" ] }, + safe_commands => { default => undef, accept => [ "yes", "no" ], context => [ "global" ] }, snapshot_qgroup_destroy => { default => undef, accept => [ "yes", "no" ], context => [ "global", "volume", "subvolume" ] }, target_qgroup_destroy => { default => undef, accept => [ "yes", "no" ] }, @@ -357,6 +359,7 @@ my $tree_inject_id = 0; # fake subvolume id for injected nodes (negative) my $fake_uuid_prefix = 'XXXXXXXX-XXXX-XXXX-XXXX-'; # plus 0-padded inject_id: XXXXXXXX-XXXX-XXXX-XXXX-000000000000 my $program_name; # "btrbk" or "lsbtr", default to "btrbk" +my $safe_commands; my $dryrun; my $loglevel = 1; my $quiet; @@ -793,8 +796,9 @@ sub _safe_cmd($;$) $_ = $_->{unsafe}; die "cannot quote leading dash for command: $_" if(/^-/); # NOTE: all files must be absolute - if($offending && !defined(check_file($_, { absolute => 1 }))) { - push @$offending, $_; + if($offending) { + push @$offending, $_ unless(defined(check_file($_, { absolute => 1 }))); + push @$offending, $_ unless(!$safe_commands || /^($safe_file_match)$/); } $_ = $prefix . quoteshell($_) . $postfix; } @@ -5656,6 +5660,7 @@ MAIN: ERROR "Configuration file not found: " . join(', ', @config_src); exit 2; } + $safe_commands = config_key($config, 'safe_commands'); unless(ref($config->{SUBSECTION}) eq "ARRAY") { ERROR "No volumes defined in configuration file";