From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id BBF441FF0B0 for ; Tue, 27 Oct 2026 11:14:05 +0100 (CET) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 4AAF6216C5; Tue, 27 Oct 2026 11:13:32 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=genua.de; s=202307; t=1793095946; bh=RNipEhxF6p5PaSsD0kxg/2A+hZYAyxBC4AKGXrxmHjE=; h=Date:From:To:Subject:References:In-Reply-To:From; b=EddBy2qOCpMRJNlzeqty8Vk8AfKK9eruoWP1kgh6O9bLb7yVaqLbGHGiGc37RDvPd tS7fbp35aCmtxXvvJDA9rT7G6x3Y+AqKDuzZNqCBpN8WU6edIBve382xIK7nLjZNT7 GpuMu7pwLHpWQ0jbmrQS3qvSFBz5U8XfLLGRWUlxDf+a4lEcEsonUOD5s+fbpY5a6a sRpAX/N7KrAq4tqWdAhdnts6NyBGKNq/muvMO/VCQmbEGoU3qZZ4ILGn9Nh6B5NBtJ MDA8jRsZvHFuWYbeHieaQ70FFyzK27nMRmOrE2JhrNHhCUGvd4aX87GlXmHra8/SXe 6SUQpwDN3oAeA== Date: Tue, 27 Oct 2026 11:12:25 +0100 From: Christian Ludwig To: Subject: [PATCH qemu-server v3 11/19] api: check the custom firmware of the bios option Message-ID: References: MIME-Version: 1.0 In-Reply-To: X-Originating-IP: [192.168.217.185] X-ClientProxiedBy: kch1-mta07.win.genua.de (10.208.16.107) To kch1-mta07.win.genua.de (10.208.16.107) Content-Type: text/plain; charset="us-ascii" Content-Disposition: inline X-SPAM-LEVEL: Spam detection results: 0 AWL 0.065 Adjusted score from AWL reputation of From: address DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DKIM_VALID -0.1 Message has at least one valid DKIM or DK signature DKIM_VALID_AU -0.1 Message has a valid DKIM or DK signature from author's domain DKIM_VALID_EF -0.1 Message has a valid DKIM or DK signature from envelope-from domain DMARC_PASS -0.1 DMARC pass policy SPF_HELO_PASS -0.001 SPF: HELO matches SPF record SPF_PASS -0.001 SPF: sender matches SPF record UNPARSEABLE_RELAY 0.001 Informational: message has unparseable relay lines Message-ID-Hash: Q55JWB2TKS5KRQVH2DJDEVJ5NGXXGVBP X-Message-ID-Hash: Q55JWB2TKS5KRQVH2DJDEVJ5NGXXGVBP X-MailFrom: christian_ludwig@genua.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: When the bios option is set via the POST/PUT {vmid}/config endpoints, check that the user may access the custom firmware image, that it is an efi-firmware volume, and that the BIOS type is 'ovmf'. Like for ISO images, whether the image is usable on the node is only checked when the VM is started. The option keeps requiring the VM.Config.Options permission. A cloned VM references the same firmware image, like an ISO image, so a clone is only considered shared if the image is on a shared storage. Report custom firmware images in the local disks of the migration precondition check, so that clients can tell why a migration is not possible. Signed-off-by: Christian Ludwig --- src/PVE/API2/Qemu.pm | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/PVE/API2/Qemu.pm b/src/PVE/API2/Qemu.pm index 922c6599..3338edc2 100644 --- a/src/PVE/API2/Qemu.pm +++ b/src/PVE/API2/Qemu.pm @@ -29,6 +29,7 @@ use PVE::GuestImport; use PVE::QemuConfig; use PVE::QemuServer; use PVE::QemuServer::Agent; +use PVE::QemuServer::BIOS; use PVE::QemuServer::Blockdev; use PVE::QemuServer::BlockJob; use PVE::QemuServer::Cloudinit; @@ -107,6 +108,20 @@ my $foreach_volume_with_alloc = sub { } }; +my $check_bios_param = sub { + my ($param) = @_; + + return if !defined($param->{bios}); + + eval { + PVE::QemuServer::BIOS::check_bios(PVE::QemuServer::BIOS::parse_bios($param->{bios})); + }; + if (my $err = $@) { + chomp($err); + raise_param_exc({ bios => $err }); + } +}; + my $check_drive_param = sub { my ($param, $storecfg, $extra_checks) = @_; @@ -277,6 +292,13 @@ my $check_storage_access = sub { "/storage/$settings->{vmstatestorage}", ['Datastore.AllocateSpace'], ) if defined($settings->{vmstatestorage}); + + if (defined($settings->{bios})) { + my $firmware = PVE::QemuServer::BIOS::parse_bios($settings->{bios})->{firmware}; + PVE::Storage::check_volume_access( + $rpcenv, $authuser, $storecfg, $vmid, $firmware, 'efi-firmware', + ) if defined($firmware); + } }; my $check_storage_access_clone = sub { @@ -319,6 +341,13 @@ my $check_storage_access_clone = sub { $rpcenv->check($authuser, "/storage/$conf->{vmstatestorage}", ['Datastore.AllocateSpace']) if defined($conf->{vmstatestorage}); + # like ISO images, a custom firmware image is simply referenced by the clone + if (my $firmware = PVE::QemuServer::BIOS::get_bios_firmware($conf)) { + my ($sid) = PVE::Storage::parse_volume_id($firmware); + my $scfg = PVE::Storage::storage_config($storecfg, $sid); + $sharedvm = 0 if !$scfg->{shared}; + } + return $sharedvm; }; @@ -1365,6 +1394,7 @@ __PACKAGE__->register_method({ &$check_cpu_model_access($rpcenv, $authuser, $param); $check_drive_param->($param, $storecfg); + $check_bios_param->($param); PVE::QemuServer::Network::add_random_macs($param); } @@ -2203,6 +2233,8 @@ my $update_vm_api = sub { $rpcenv, $authuser, $storecfg, $vmid, $param, undef, $extraction_storage, ); + $check_bios_param->($param); + PVE::QemuServer::check_bridge_access($rpcenv, $authuser, $param); my $load_and_check_config = sub { @@ -5348,6 +5380,11 @@ __PACKAGE__->register_method({ type => 'boolean', description => 'True if the disk is a cdrom.', }, + is_firmware => { + type => 'boolean', + description => 'True if the volume is a custom firmware image.', + optional => 1, + }, is_unused => { type => 'boolean', description => 'True if the disk is unused.', -- 2.34.1