]> git.proxmox.com Git - pve-container.git/commitdiff
create: fix passing of template file descriptor
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Wed, 21 Mar 2018 08:57:47 +0000 (09:57 +0100)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Wed, 21 Mar 2018 11:29:33 +0000 (12:29 +0100)
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@proxmox.com>
src/PVE/LXC/Create.pm

index 2a37d930b50e62817753ddc8bf9ffc31888fc75c..d8f8f04969db3710ab6ad794ec720ba8be976eab 100644 (file)
@@ -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;