[pve-devel] [PATCH v2 container 1/2] create: fix passing of template file descriptor

Wolfgang Bumiller w.bumiller at proxmox.com
Wed Mar 21 09:57:47 CET 2018


This finishes the work started with 07084526aa4a ("create:
open templates as real root"), which opened templates as
real root, but passed it to tar via /proc/*/fd, which does
not actually bypass the check. (Curiously tar did manage to
figure out the file extension from it).

In order to actually extract templates the unprivileged user
cannot access by themselves, we need to pass it to tar via
stdin, however, this means tar cannot auto-detect the
compression (or more accurately, it can and does, but tells
you which option to pass it rather than just extracting
it...)

Signed-off-by: Wolfgang Bumiller <w.bumiller at proxmox.com>
---
Changes to v1:
  - Using a %compression_map instead of a ?: chain, since it apparently
    wasn't pretty enough ;-)

 src/PVE/LXC/Create.pm | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/src/PVE/LXC/Create.pm b/src/PVE/LXC/Create.pm
index 2a37d93..d8f8f04 100644
--- a/src/PVE/LXC/Create.pm
+++ b/src/PVE/LXC/Create.pm
@@ -65,16 +65,31 @@ sub restore_archive {
     my $userns_cmd = PVE::LXC::userns_command($id_map);
 
     my $archive_fh;
-    my $tar_input_file = '-';
+    my $tar_input = '<&STDIN';
+    my @compression_opt;
     if ($archive ne '-') {
+	# GNU tar refuses to autodetect this... *sigh*
+	my %compression_map = (
+	    '.gz'  => '-z',
+	    '.bz2' => '-j',
+	    '.xz'  => '-J',
+	);
+	if ($archive =~ /\.tar(\.[^.]+)?$/) {
+	    if (defined($1)) {
+		@compression_opt = $compression_map{$1}
+		    or die "unrecognized compression format: $1\n";
+	    }
+	} else {
+	    die "file does not look like a template archive: $archive\n";
+	}
 	sysopen($archive_fh, $archive, O_RDONLY)
 	    or die "failed to open '$archive': $!\n";
-	$tar_input_file = '/proc/self/fd/'.fileno($archive_fh);
 	my $flags = $archive_fh->fcntl(Fcntl::F_GETFD(), 0);
 	$archive_fh->fcntl(Fcntl::F_SETFD(), $flags & ~(Fcntl::FD_CLOEXEC()));
+	$tar_input = '<&'.fileno($archive_fh);
     }
 
-    my $cmd = [@$userns_cmd, 'tar', 'xpf', $tar_input_file, '--totals',
+    my $cmd = [@$userns_cmd, 'tar', 'xpf', '-', @compression_opt, '--totals',
                @PVE::Storage::Plugin::COMMON_TAR_FLAGS,
                '-C', $rootdir];
 
@@ -88,11 +103,10 @@ sub restore_archive {
 
     if ($archive eq '-') {
 	print "extracting archive from STDIN\n";
-	eval { PVE::Tools::run_command($cmd, input => "<&STDIN"); };
     } else {
 	print "extracting archive '$archive'\n";
-	eval { PVE::Tools::run_command($cmd); };
     }
+    eval { PVE::Tools::run_command($cmd, input => $tar_input); };
     my $err = $@;
     close($archive_fh) if defined $archive_fh;
     die $err if $err && !$no_unpack_error;
-- 
2.11.0





More information about the pve-devel mailing list