From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 644FFA06DC for ; Tue, 13 Jun 2023 14:23:37 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 492812FC8B for ; Tue, 13 Jun 2023 14:23:07 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Tue, 13 Jun 2023 14:23:06 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id DD95F44EBD for ; Tue, 13 Jun 2023 14:23:05 +0200 (CEST) Date: Tue, 13 Jun 2023 14:23:04 +0200 From: Wolfgang Bumiller To: Dominik Csapak Cc: pve-devel@lists.proxmox.com Message-ID: References: <20230606135222.984747-1-d.csapak@proxmox.com> <20230606135222.984747-4-d.csapak@proxmox.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20230606135222.984747-4-d.csapak@proxmox.com> X-SPAM-LEVEL: Spam detection results: 0 AWL -0.024 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment POISEN_SPAM_PILL 0.1 Meta: its spam POISEN_SPAM_PILL_1 0.1 random spam to be learned in bayes POISEN_SPAM_PILL_3 0.1 random spam to be learned in bayes SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record T_SCC_BODY_TEXT_LINE -0.01 - Subject: Re: [pve-devel] [PATCH qemu-server v5 1/6] enable cluster mapped USB devices for guests X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 13 Jun 2023 12:23:37 -0000 On Tue, Jun 06, 2023 at 03:52:02PM +0200, Dominik Csapak wrote: > this patch allows configuring usb devices that are mapped via > cluster resource mapping when the user has 'Resource.Use' on the ACL > path '/resource/usb/{ID}' (in addition to the usual required vm config ^ should be /mapping in the commit message as well ;-) > privileges) > > for now, this is only valid if there is exactly one mapping for the > host, since we don't track passed through usb devices yet > > this adds a permission check for clone and restore since an admin can > now give permissions for specific devices > > Signed-off-by: Dominik Csapak > --- > changes from v4: > * rename s/resource/mapping/i > * add permission check for clone/restore > > PVE/API2/Qemu.pm | 51 ++++++++++++++++++++++++++++++++++++++++--- > PVE/QemuServer.pm | 40 ++++++++++++++++++++++++++++++++- > PVE/QemuServer/USB.pm | 27 ++++++++++++++++++++--- > 3 files changed, 111 insertions(+), 7 deletions(-) > > diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm > index 587bb222..13cc73d1 100644 > --- a/PVE/API2/Qemu.pm > +++ b/PVE/API2/Qemu.pm > @@ -32,6 +32,7 @@ use PVE::QemuServer::Drive; > use PVE::QemuServer::ImportDisk; > use PVE::QemuServer::Monitor qw(mon_cmd); > use PVE::QemuServer::Machine; > +use PVE::QemuServer::USB qw(parse_usb_device); > use PVE::QemuMigrate; > use PVE::RPCEnvironment; > use PVE::AccessControl; > @@ -175,6 +176,16 @@ my $check_storage_access = sub { > if defined($settings->{vmstatestorage}); > }; > > +my sub check_mapping_access_clone { > + my ($rpcenv, $user, $conf) = @_; > + > + for my $opt (keys $conf->%*) { > + if ($opt =~ m/^usb\d+$/) { > + PVE::QemuServer::check_vm_clone_restore_usb_perm($rpcenv, $user, $opt, $conf->{$opt}) > + } > + } > +}; > + > my $check_storage_access_clone = sub { > my ($rpcenv, $authuser, $storecfg, $conf, $storage) = @_; > > @@ -590,8 +601,13 @@ my $check_vm_create_usb_perm = sub { > > foreach my $opt (keys %{$param}) { > next if $opt !~ m/^usb\d+$/; > + my $entry = PVE::JSONSchema::parse_property_string('pve-qm-usb', $param->{$opt}); > + my $device = parse_usb_device($entry->{host}); > > - if ($param->{$opt} =~ m/spice/) { > + if ($device->{spice}) { > + $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.HWType']); > + } elsif ($device->{mapped}) { > + $rpcenv->check_full($authuser, "/mapping/usb/$entry->{host}", ['Mapping.Use']); > $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.HWType']); > } else { > die "only root can set '$opt' config for real devices\n"; > @@ -1696,7 +1712,12 @@ my $update_vm_api = sub { > PVE::QemuConfig->add_to_pending_delete($conf, $opt, $force); > PVE::QemuConfig->write_config($vmid, $conf); > } elsif ($opt =~ m/^usb\d+$/) { > - if ($val =~ m/spice/) { > + my $device = PVE::JSONSchema::parse_property_string('pve-qm-usb', $val); > + my $host = parse_usb_device($device->{host}); > + if ($host->{spice}) { > + $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']); > + } elsif ($host->{mapped}) { > + $rpcenv->check_full($authuser, "/mapping/usb/$device->{host}", ['Mapping.Use']); > $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']); > } elsif ($authuser ne 'root@pam') { > die "only root can delete '$opt' config for real devices\n"; > @@ -1761,7 +1782,30 @@ my $update_vm_api = sub { > } > $conf->{pending}->{$opt} = $param->{$opt}; > } elsif ($opt =~ m/^usb\d+/) { > - if ((!defined($conf->{$opt}) || $conf->{$opt} =~ m/spice/) && $param->{$opt} =~ m/spice/) { > + my $olddevice; > + my $oldhost; > + if (defined($conf->{$opt})) { > + $olddevice = PVE::JSONSchema::parse_property_string('pve-qm-usb', $conf->{$opt}); > + $oldhost = parse_usb_device($olddevice->{host}); > + } > + if (defined($oldhost)) { > + if ($oldhost->{spice}) { > + $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']); > + } elsif ($oldhost->{mapped}) { > + $rpcenv->check_full($authuser, "/mapping/usb/$olddevice->{host}", ['Mapping.Use']); > + $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']); > + } elsif ($authuser ne 'root@pam') { > + die "only root can modify '$opt' config for real devices\n"; > + } > + } > + > + my $newdevice = PVE::JSONSchema::parse_property_string('pve-qm-usb', $param->{$opt}); > + my $newhost = parse_usb_device($newdevice->{host}); > + > + if ($newhost->{spice}) { > + $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']); > + } elsif ($newhost->{mapped}) { > + $rpcenv->check_full($authuser, "/mapping/usb/$newdevice->{host}", ['Mapping.Use']); > $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']); > } elsif ($authuser ne 'root@pam') { > die "only root can modify '$opt' config for real devices\n"; > @@ -3488,6 +3532,7 @@ __PACKAGE__->register_method({ > my $oldconf = $snapname ? $conf->{snapshots}->{$snapname} : $conf; > > my $sharedvm = &$check_storage_access_clone($rpcenv, $authuser, $storecfg, $oldconf, $storage); > + check_mapping_access_clone($rpcenv, $authuser, $oldconf); > > die "can't clone VM to node '$target' (VM uses local storage)\n" > if $target && !$sharedvm; > diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm > index ab33aa37..f209a604 100644 > --- a/PVE/QemuServer.pm > +++ b/PVE/QemuServer.pm > @@ -1090,6 +1090,8 @@ The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is: > > You can use the 'lsusb -t' command to list existing usb devices. > > +Alternatively, you can used an ID of a mapped usb device. > + > NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such > machines - use with special care. > > @@ -1106,6 +1108,8 @@ EODESCR > }, > }; > > +PVE::JSONSchema::register_format('pve-qm-usb', $usb_fmt); > + > my $usbdesc = { > optional => 1, > type => 'string', format => $usb_fmt, > @@ -2243,7 +2247,12 @@ PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device); > sub verify_usb_device { > my ($value, $noerr) = @_; > > - return $value if parse_usb_device($value); > + my $parsed = eval { parse_usb_device($value) }; > + if (my $err = $@) { > + die $@ if !$noerr; (should use $err instead of $@ since you already assigned it) > + return; > + } > + return $value if defined($parsed); > > return if $noerr; >