[pve-devel] [RFC pve-container 2/6] LXC::Setup: id_map support for file wrappers
Wolfgang Bumiller
w.bumiller at proxmox.com
Thu Nov 12 14:00:25 CET 2015
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 | 33 +++++++++++++++++++++++++++++++++
src/PVE/LXC/Create.pm | 9 +++++----
src/PVE/LXC/Setup.pm | 8 ++++++++
src/PVE/LXC/Setup/Base.pm | 34 +++++++++++++++++++++++++++++-----
4 files changed, 75 insertions(+), 9 deletions(-)
diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm
index dc6d318..f38c5bd 100644
--- a/src/PVE/LXC.pm
+++ b/src/PVE/LXC.pm
@@ -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;
diff --git a/src/PVE/LXC/Create.pm b/src/PVE/LXC/Create.pm
index be90d66..5f76b88 100644
--- a/src/PVE/LXC/Create.pm
+++ b/src/PVE/LXC/Create.pm
@@ -28,10 +28,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,
diff --git a/src/PVE/LXC/Setup.pm b/src/PVE/LXC/Setup.pm
index 9dde1e8..dc1457a 100644
--- a/src/PVE/LXC/Setup.pm
+++ b/src/PVE/LXC/Setup.pm
@@ -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;
}
diff --git a/src/PVE/LXC/Setup/Base.pm b/src/PVE/LXC/Setup/Base.pm
index d114fb3..0d50583 100644
--- a/src/PVE/LXC/Setup/Base.pm
+++ b/src/PVE/LXC/Setup/Base.pm
@@ -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;
--
2.1.4
More information about the pve-devel
mailing list