use warnings;
use Cwd qw();
-use Errno qw(ELOOP ENOTDIR EROFS ECONNREFUSED EEXIST);
-use Fcntl qw(O_RDONLY O_WRONLY O_NOFOLLOW O_DIRECTORY);
+use Errno qw(ELOOP ENOENT ENOTDIR EROFS ECONNREFUSED EEXIST);
+use Fcntl qw(O_RDONLY O_WRONLY O_NOFOLLOW O_DIRECTORY :mode);
use File::Path;
use File::Spec;
use IO::Poll qw(POLLIN POLLHUP);
$raw .= "lxc.mount.auto = sys:mixed\n";
}
+ PVE::LXC::Config->foreach_passthrough_device($conf, sub {
+ my ($key, $device) = @_;
+
+ die "Path is not defined for passthrough device $key"
+ unless (defined($device->{path}));
+
+ my $absolute_path = $device->{path};
+ my ($mode, $rdev) = (stat($absolute_path))[2, 6];
+
+ die "Device $absolute_path does not exist\n" if $! == ENOENT;
+
+ die "Error accessing device $absolute_path\n"
+ if (!defined($mode) || !defined($rdev));
+
+ die "$absolute_path is not a device\n"
+ if (!S_ISBLK($mode) && !S_ISCHR($mode));
+
+ my $major = PVE::Tools::dev_t_major($rdev);
+ my $minor = PVE::Tools::dev_t_minor($rdev);
+ my $device_type_char = S_ISBLK($mode) ? 'b' : 'c';
+ $raw .= "lxc.cgroup2.devices.allow = $device_type_char $major:$minor rw\n";
+ });
+
# WARNING: DO NOT REMOVE this without making sure that loop device nodes
# cannot be exposed to the container with r/w access (cgroup perms).
# When this is enabled mounts will still remain in the monitor's namespace
warn $@ if $@;
PVE::Network::SDN::Vnets::add_next_free_cidr($newnet->{bridge}, $conf->{hostname}, $newnet->{hwaddr}, $vmid, undef, 1);
- PVE::Network::SDN::Vnets::add_dhcp_mapping($newnet->{bridge}, $newnet->{hwaddr});
+ PVE::Network::SDN::Vnets::add_dhcp_mapping($newnet->{bridge}, $newnet->{hwaddr}, $vmid, $conf->{hostname});
}
delete $conf->{$opt};
PVE::LXC::Config->write_config($vmid, $conf);
}
} else {
- PVE::Network::SDN::Vnets::add_next_free_cidr($newnet->{bridge}, $conf->{hostname}, $newnet->{hwaddr}, $vmid, undef, 1);
- PVE::Network::SDN::Vnets::add_dhcp_mapping($newnet->{bridge}, $newnet->{hwaddr});
+ if ($have_sdn) {
+ PVE::Network::SDN::Vnets::add_next_free_cidr($newnet->{bridge}, $conf->{hostname}, $newnet->{hwaddr}, $vmid, undef, 1);
+ PVE::Network::SDN::Vnets::add_dhcp_mapping($newnet->{bridge}, $newnet->{hwaddr}, $vmid, $conf->{hostname});
+ }
hotplug_net($vmid, $conf, $opt, $newnet, $netid);
}
$rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.Network']);
check_bridge_access($rpcenv, $authuser, $oldconf->{$opt}) if $oldconf->{$opt};
check_bridge_access($rpcenv, $authuser, $newconf->{$opt}) if $newconf->{$opt};
+ } elsif ($opt =~ m/^dev\d+$/) {
+ raise_perm_exc("configuring device passthrough is only allowed for root\@pam");
} elsif ($opt eq 'nameserver' || $opt eq 'searchdomain' || $opt eq 'hostname') {
$rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.Network']);
} elsif ($opt eq 'features') {
my $dir = get_staging_mount_path($opt);
# Now switch our apparmor profile before mounting:
- my $data = 'changeprofile /usr/bin/lxc-start';
+ my $data = 'changeprofile pve-container-mounthotplug';
if (syswrite($aa_fd, $data, length($data)) != length($data)) {
die "failed to change apparmor profile: $!\n";
}
}
}
+sub map_ct_id_to_host {
+ my ($id, $id_map, $id_type) = @_;
+
+ for my $mapping (@$id_map) {
+ my ($type, $ct, $host, $length) = @$mapping;
+
+ next if ($type ne $id_type);
+
+ if ($id >= $ct && $id < ($ct + $length)) {
+ return $host - $ct + $id;
+ }
+ }
+
+ return $id;
+}
+
+sub map_ct_uid_to_host {
+ my ($uid, $id_map) = @_;
+
+ return map_ct_id_to_host($uid, $id_map, 'u');
+}
+
+sub map_ct_gid_to_host {
+ my ($gid, $id_map) = @_;
+
+ return map_ct_id_to_host($gid, $id_map, 'g');
+}
+
sub userns_command {
my ($id_map) = @_;
if (@$id_map) {
for my $opt (keys %$conf) {
next if $opt !~ m/^net(\d+)$/;
- my $net = PVE::QemuServer::parse_net($conf->{$opt});
+ my $net = PVE::LXC::Config->parse_lxc_network($conf->{$opt});
next if $net->{type} ne 'veth';
- PVE::Network::SDN::Vnets::add_next_free_cidr($net->{bridge}, $conf->{hostname}, $net->{hwaddr}, $vmid, undef, 1);
+ PVE::Network::SDN::Vnets::add_next_free_cidr($net->{bridge}, $conf->{hostname}, $net->{hwaddr}, $vmid, undef, 1);
}
}
for my $opt (keys %$conf) {
next if $opt !~ m/^net(\d+)$/;
- my $net = PVE::QemuServer::parse_net($conf->{$opt});
+ my $net = PVE::LXC::Config->parse_lxc_network($conf->{$opt});
eval { PVE::Network::SDN::Vnets::del_ips_from_mac($net->{bridge}, $net->{hwaddr}, $conf->{hostname}) };
warn $@ if $@;
}