]> git.proxmox.com Git - pve-container.git/commitdiff
LXC::Setup: id_map support for file wrappers
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Thu, 12 Nov 2015 13:00:25 +0000 (14:00 +0100)
committerDietmar Maurer <dietmar@proxmox.com>
Fri, 13 Nov 2015 10:39:36 +0000 (11:39 +0100)
when an id_map is configured for the container or the
unprivileged flag set (which implies the default userid
map), the file access wrappers (LXC::Setup::Plugin::ct_*
functions) will use the id_map to fixup ownership of created
files.

src/PVE/LXC.pm
src/PVE/LXC/Create.pm
src/PVE/LXC/Setup.pm
src/PVE/LXC/Setup/Base.pm

index dc6d318bee7392a157afecd00d30326d158f9e4a..f38c5bdc0c97f404b3a508f55ea82022f54e09ba 100644 (file)
@@ -2356,4 +2356,37 @@ sub complete_ctid_running {
     return &$complete_ctid_full(1);
 }
 
+sub parse_id_maps {
+    my ($conf) = @_;
+
+    my $id_map = [];
+    my $rootuid = 0;
+    my $rootgid = 0;
+
+    my $lxc = $conf->{lxc};
+    foreach my $entry (@$lxc) {
+       my ($key, $value) = @$entry;
+       next if $key ne 'lxc.id_map';
+       if ($value =~ /^([ug])\s+(\d+)\s+(\d+)\s+(\d+)\s*$/) {
+           my ($type, $ct, $host, $length) = ($1, $2, $3, $4);
+           push @$id_map, [$type, $ct, $host, $length];
+           if ($ct == 0) {
+               $rootuid = $host if $type eq 'u';
+               $rootgid = $host if $type eq 'g';
+           }
+       } else {
+           die "failed to parse id_map: $value\n";
+       }
+    }
+
+    if (!@$id_map && $conf->{unprivileged}) {
+       # Should we read them from /etc/subuid?
+       $id_map = [ ['u', '0', '100000', '65536'],
+                   ['g', '0', '100000', '65536'] ];
+       $rootuid = $rootgid = 100000;
+    }
+
+    return ($id_map, $rootuid, $rootgid);
+}
+
 1;
index be90d668a5887aed91357421e1b969633e1f0687..cb9bbff83358a96ad4931be516ffe64060480397 100644 (file)
@@ -27,11 +27,11 @@ sub restore_archive {
 
     my $userns_cmd = [];
 
-#    we always use the same mapping: 'b:0:100000:65536'
-#    if ($conf->{'lxc.id_map'}) {
-#      $userns_cmd = ['lxc-usernsexec', '-m', 'b:0:100000:65536', '--'];
-#      PVE::Tools::run_command(['chown', '-R', '100000:100000', $rootdir]);
-#    }
+    my ($id_map, $rootuid, $rootgid) = PVE::LXC::parse_id_maps($conf);
+    if (@$id_map) {
+       $userns_cmd = ['lxc-usernsexec', (map { ('-m', join(':', @$_)) } @$id_map), '--'];
+       PVE::Tools::run_command(['chown', '-R', "$rootuid:$rootgid", $rootdir]);
+    }
 
     my $cmd = [@$userns_cmd, 'tar', 'xpf', $archive, '--totals',
                @$PVE::LXC::COMMON_TAR_FLAGS,
index 9dde1e82e836230501692375d4f53ca3aef1285f..dc1457a80996f1d323b28f83ed477f17de0fe850 100644 (file)
@@ -57,6 +57,14 @@ sub new {
 
     # Cache some host files we need access to:
     $plugin->{host_resolv_conf} = PVE::INotify::read_file('resolvconf');
+
+    # pass on user namespace information:
+    my ($id_map, $rootuid, $rootgid) = PVE::LXC::parse_id_maps($conf);
+    if (@$id_map) {
+       $plugin->{id_map} = $id_map;
+       $plugin->{rootuid} = $rootuid;
+       $plugin->{rootgid} = $rootgid;
+    }
     
     return $self;
 }
index d114fb3f52a2e07f590b513a62f8b189a6bcc543..0d50583acce24d6b3d29ed8271458b3e58bc033f 100644 (file)
@@ -443,11 +443,23 @@ sub post_create_hook {
 # File access wrappers for container setup code.
 # For user-namespace support these might need to take uid and gid maps into account.
 
+sub ct_reset_ownership {
+    my ($self, @files) = @_;
+    my $conf = $self->{conf};
+    return if !$self->{id_map};
+    my $uid = $self->{rootuid};
+    my $gid = $self->{rootgid};
+    chown($uid, $gid, @files);
+}
+
 sub ct_mkdir {
     my ($self, $file, $mask) = @_;
     # mkdir goes by parameter count - an `undef' mode acts like a mode of 0000
-    return CORE::mkdir($file, $mask) if defined ($mask);
-    return CORE::mkdir($file);
+    if (defined($mask)) {
+       return CORE::mkdir($file, $mask) && $self->ct_reset_ownership($file);
+    } else {
+       return CORE::mkdir($file) && $self->ct_reset_ownership($file);
+    }
 }
 
 sub ct_unlink {
@@ -471,12 +483,23 @@ sub ct_open_file_read {
 sub ct_open_file_write {
     my $self = shift;
     my $file = shift;
-    return IO::File->new($file, O_WRONLY | O_CREAT, @_);
+    my $fh = IO::File->new($file, O_WRONLY | O_CREAT, @_);
+    $self->ct_reset_ownership($fh);
+    return $fh;
 }
 
 sub ct_make_path {
     my $self = shift;
-    File::Path::make_path(@_);
+    if ($self->{id_map}) {
+       my $opts = pop;
+       if (ref($opts) eq 'HASH') {
+           $opts->{owner} = $self->{rootuid} if !defined($self->{owner});
+           $opts->{group} = $self->{rootgid} if !defined($self->{group});
+       }
+       File::Path::make_path(@_, $opts);
+    } else {
+       File::Path::make_path(@_);
+    }
 }
 
 sub ct_symlink {
@@ -516,7 +539,8 @@ sub ct_file_get_contents {
 
 sub ct_file_set_contents {
     my ($self, $file, $data, $perms) = @_;
-    return PVE::Tools::file_set_contents($file, $data, $perms);
+    PVE::Tools::file_set_contents($file, $data, $perms);
+    $self->ct_reset_ownership($file);
 }
 
 1;