public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user
@ 2025-02-10 15:37 Filip Schauer
  2025-02-10 15:37 ` [pve-devel] [PATCH guest-common v3 01/11] mapping: add a hardware RNG mapping config Filip Schauer
                   ` (11 more replies)
  0 siblings, 12 replies; 16+ messages in thread
From: Filip Schauer @ 2025-02-10 15:37 UTC (permalink / raw)
  To: pve-devel

Allow users with the VM.Config.HWType privilege to configure VirtIO RNG
devices on VMs with either /dev/urandom or /dev/random as the entropy
source.

Further introduce hardware RNG device mapping to be able to selectively
allow non-root users with the Mapping.Use privilege to configure
hardware RNG devices as entropy sources.

Changes since v2:
* Restrict RNG device format to enum of
* Add descriptive commit message
* Code style fixes
* Remove outdated remarks about entropy stravation of /dev/random
* Split helpers for VirtIO RNG command line arguments into its own
  commit
* Add explicit "use PVE::QemuServer::RNG;" statement to PVE/API2/Qemu.pm
* Fix "map: type check ('array') failed" error when adding a mapping in
  the UI
* ui: split resource mapping types into tabbed views

Changes since v1:
* Restrict use of /dev/hwrng to the root user
* introduce hardware RNG mapping

pve-guest-common:

Filip Schauer (1):
  mapping: add a hardware RNG mapping config

 src/Makefile             |   1 +
 src/PVE/Mapping/HWRNG.pm | 147 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 148 insertions(+)
 create mode 100644 src/PVE/Mapping/HWRNG.pm


pve-cluster:

Filip Schauer (1):
  cfs: add 'mapping/hwrng.cfg' to observed files

 src/PVE/Cluster.pm  | 1 +
 src/pmxcfs/status.c | 1 +
 2 files changed, 2 insertions(+)


pve-manager:

Filip Schauer (5):
  introduce hardware rng mapping api
  introduce hardware rng scanning api
  ui: add hardware RNG resource mapping
  ui: allow use of mapped hardware RNGs as entropy sources for VMs
  ui: split resource mapping types into tabbed views

 PVE/API2/Cluster/Mapping.pm                   |   7 +
 PVE/API2/Cluster/Mapping/HWRNG.pm             | 286 ++++++++++++++++++
 PVE/API2/Cluster/Mapping/Makefile             |   5 +-
 PVE/API2/Hardware.pm                          |   7 +
 PVE/API2/Hardware/HWRNG.pm                    |  47 +++
 PVE/API2/Hardware/Makefile                    |   1 +
 www/manager6/Makefile                         |  12 +-
 www/manager6/data/PermPathStore.js            |   1 +
 www/manager6/dc/Config.js                     |  41 +--
 www/manager6/form/HWRNGMapSelector.js         |  99 ++++++
 www/manager6/qemu/HardwareView.js             |   9 +-
 www/manager6/qemu/RNGEdit.js                  |  79 +++--
 www/manager6/resource-map/HWRNGMapEdit.js     | 149 +++++++++
 www/manager6/resource-map/HWRNGMapView.js     |  76 +++++
 .../{window => resource-map}/PCIMapEdit.js    |   2 +-
 .../{dc => resource-map}/PCIMapView.js        |   4 +-
 www/manager6/resource-map/ResourceMapView.js  |  23 ++
 .../{window => resource-map}/USBMapEdit.js    |   2 +-
 .../{dc => resource-map}/USBMapView.js        |   4 +-
 19 files changed, 778 insertions(+), 76 deletions(-)
 create mode 100644 PVE/API2/Cluster/Mapping/HWRNG.pm
 create mode 100644 PVE/API2/Hardware/HWRNG.pm
 create mode 100644 www/manager6/form/HWRNGMapSelector.js
 create mode 100644 www/manager6/resource-map/HWRNGMapEdit.js
 create mode 100644 www/manager6/resource-map/HWRNGMapView.js
 rename www/manager6/{window => resource-map}/PCIMapEdit.js (99%)
 rename www/manager6/{dc => resource-map}/PCIMapView.js (96%)
 create mode 100644 www/manager6/resource-map/ResourceMapView.js
 rename www/manager6/{window => resource-map}/USBMapEdit.js (99%)
 rename www/manager6/{dc => resource-map}/USBMapView.js (95%)


qemu-server:

Filip Schauer (4):
  refactor: move rng related code into its own module
  add helpers for VirtIO RNG command line arguments
  allow non-root users to set /dev/u?random as an RNG source
  let VirtIO RNG devices source entropy from mapped HWRNGs

 PVE/API2/Qemu.pm        |  48 +++++++++++++
 PVE/QemuServer.pm       |  97 ++++++-------------------
 PVE/QemuServer/Makefile |   1 +
 PVE/QemuServer/RNG.pm   | 153 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 224 insertions(+), 75 deletions(-)
 create mode 100644 PVE/QemuServer/RNG.pm


Summary over all repositories:
  27 files changed, 1152 insertions(+), 151 deletions(-)

-- 
Generated by git-murpp 0.6.0


_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [pve-devel] [PATCH guest-common v3 01/11] mapping: add a hardware RNG mapping config
  2025-02-10 15:37 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Filip Schauer
@ 2025-02-10 15:37 ` Filip Schauer
  2025-02-10 15:37 ` [pve-devel] [PATCH cluster v3 02/11] cfs: add 'mapping/hwrng.cfg' to observed files Filip Schauer
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Filip Schauer @ 2025-02-10 15:37 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 src/Makefile             |   1 +
 src/PVE/Mapping/HWRNG.pm | 147 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 148 insertions(+)
 create mode 100644 src/PVE/Mapping/HWRNG.pm

diff --git a/src/Makefile b/src/Makefile
index cbc40c1..ae62b7d 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -15,6 +15,7 @@ install: PVE
 	install -m 0644 PVE/StorageTunnel.pm ${PERL5DIR}/PVE/
 	install -m 0644 PVE/Tunnel.pm ${PERL5DIR}/PVE/
 	install -d ${PERL5DIR}/PVE/Mapping
+	install -m 0644 PVE/Mapping/HWRNG.pm ${PERL5DIR}/PVE/Mapping/
 	install -m 0644 PVE/Mapping/PCI.pm ${PERL5DIR}/PVE/Mapping/
 	install -m 0644 PVE/Mapping/USB.pm ${PERL5DIR}/PVE/Mapping/
 	install -d ${PERL5DIR}/PVE/VZDump
diff --git a/src/PVE/Mapping/HWRNG.pm b/src/PVE/Mapping/HWRNG.pm
new file mode 100644
index 0000000..3e6bc9b
--- /dev/null
+++ b/src/PVE/Mapping/HWRNG.pm
@@ -0,0 +1,147 @@
+package PVE::Mapping::HWRNG;
+
+use strict;
+use warnings;
+
+use PVE::Cluster qw(
+    cfs_lock_file
+    cfs_read_file
+    cfs_register_file
+    cfs_write_file
+);
+use PVE::INotify ();
+use PVE::JSONSchema qw(get_standard_option parse_property_string);
+
+use base qw(PVE::SectionConfig);
+
+my $FILENAME = 'mapping/hwrng.cfg';
+
+cfs_register_file($FILENAME,
+		  sub { __PACKAGE__->parse_config(@_); },
+		  sub { __PACKAGE__->write_config(@_); });
+
+
+# so we don't have to repeat the type every time
+sub parse_section_header {
+    my ($class, $line) = @_;
+
+    if ($line =~ m/^(\S+)\s*$/) {
+	my $id = $1;
+	my $errmsg = undef; # set if you want to skip whole section
+	eval { PVE::JSONSchema::pve_verify_configid($id) };
+	$errmsg = $@ if $@;
+	my $config = {}; # to return additional attributes
+	return ('hwrng', $id, $errmsg, $config);
+    }
+    return undef;
+}
+
+sub format_section_header {
+    my ($class, $type, $sectionId, $scfg, $done_hash) = @_;
+
+    return "$sectionId\n";
+}
+
+sub type {
+    return 'hwrng';
+}
+
+my $map_fmt = {
+    node => get_standard_option('pve-node'),
+    path => {
+	description => "The path to the device node of the entropy source.",
+	type => 'string',
+	enum => ['/dev/urandom', '/dev/random', '/dev/hwrng'],
+    },
+    description => {
+	description => "Description of the node specific device.",
+	type => 'string',
+	optional => 1,
+	maxLength => 4096,
+    },
+};
+
+my $defaultData = {
+    propertyList => {
+	id => {
+	    type => 'string',
+	    description => "The ID of the logical HWRNG mapping.",
+	    format => 'pve-configid',
+	},
+	description => {
+	    description => "Description of the logical HWRNG device.",
+	    type => 'string',
+	    optional => 1,
+	    maxLength => 4096,
+	},
+	map => {
+	    type => 'array',
+	    description => 'A list of maps for the cluster nodes.',
+	    items => {
+		type => 'string',
+		format => $map_fmt,
+	    },
+	},
+    },
+};
+
+sub private {
+    return $defaultData;
+}
+
+sub options {
+    return {
+	description => { optional => 1 },
+	map => {},
+    };
+}
+
+sub config {
+    return cfs_read_file($FILENAME);
+}
+
+sub lock_hwrng_config {
+    my ($code, $errmsg) = @_;
+
+    cfs_lock_file($FILENAME, undef, $code);
+    if (my $err = $@) {
+	$errmsg ? die "$errmsg: $err" : die $err;
+    }
+}
+
+sub write_hwrng_config {
+    my ($cfg) = @_;
+
+    cfs_write_file($FILENAME, $cfg);
+}
+
+sub find_on_current_node {
+    my ($id) = @_;
+
+    my $cfg = config();
+    my $node = PVE::INotify::nodename();
+
+    return get_node_mapping($cfg, $id, $node);
+}
+
+sub get_node_mapping {
+    my ($cfg, $id, $nodename) = @_;
+
+    return undef if !defined($cfg->{ids}->{$id});
+
+    my $res = [];
+    for my $map ($cfg->{ids}->{$id}->{map}->@*) {
+	my $entry = eval { parse_property_string($map_fmt, $map) };
+	warn $@ if $@;
+	if ($entry && $entry->{node} eq $nodename) {
+	    push $res->@*, $entry;
+	}
+    }
+
+    return $res;
+}
+
+PVE::Mapping::HWRNG->register();
+PVE::Mapping::HWRNG->init();
+
+1;
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [pve-devel] [PATCH cluster v3 02/11] cfs: add 'mapping/hwrng.cfg' to observed files
  2025-02-10 15:37 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Filip Schauer
  2025-02-10 15:37 ` [pve-devel] [PATCH guest-common v3 01/11] mapping: add a hardware RNG mapping config Filip Schauer
@ 2025-02-10 15:37 ` Filip Schauer
  2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 03/11] introduce hardware rng mapping api Filip Schauer
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Filip Schauer @ 2025-02-10 15:37 UTC (permalink / raw)
  To: pve-devel

Observe the configuration file for hardware RNG mappings.

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 src/PVE/Cluster.pm  | 1 +
 src/pmxcfs/status.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/src/PVE/Cluster.pm b/src/PVE/Cluster.pm
index e0e3ee9..684b481 100644
--- a/src/PVE/Cluster.pm
+++ b/src/PVE/Cluster.pm
@@ -84,6 +84,7 @@ my $observed = {
     'sdn/.running-config' => 1,
     'virtual-guest/cpu-models.conf' => 1,
     'virtual-guest/profiles.cfg' => 1,
+    'mapping/hwrng.cfg' => 1,
     'mapping/pci.cfg' => 1,
     'mapping/usb.cfg' => 1,
 };
diff --git a/src/pmxcfs/status.c b/src/pmxcfs/status.c
index ff5fcc4..7001dfa 100644
--- a/src/pmxcfs/status.c
+++ b/src/pmxcfs/status.c
@@ -114,6 +114,7 @@ static memdb_change_t memdb_change_array[] = {
 	{ .path = "virtual-guest/cpu-models.conf" },
 	{ .path = "virtual-guest/profiles.cfg" },
 	{ .path = "firewall/cluster.fw" },
+	{ .path = "mapping/hwrng.cfg" },
 	{ .path = "mapping/pci.cfg" },
 	{ .path = "mapping/usb.cfg" },
 };
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [pve-devel] [PATCH manager v3 03/11] introduce hardware rng mapping api
  2025-02-10 15:37 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Filip Schauer
  2025-02-10 15:37 ` [pve-devel] [PATCH guest-common v3 01/11] mapping: add a hardware RNG mapping config Filip Schauer
  2025-02-10 15:37 ` [pve-devel] [PATCH cluster v3 02/11] cfs: add 'mapping/hwrng.cfg' to observed files Filip Schauer
@ 2025-02-10 15:37 ` Filip Schauer
  2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 04/11] introduce hardware rng scanning api Filip Schauer
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Filip Schauer @ 2025-02-10 15:37 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 PVE/API2/Cluster/Mapping.pm       |   7 +
 PVE/API2/Cluster/Mapping/HWRNG.pm | 286 ++++++++++++++++++++++++++++++
 PVE/API2/Cluster/Mapping/Makefile |   5 +-
 3 files changed, 296 insertions(+), 2 deletions(-)
 create mode 100644 PVE/API2/Cluster/Mapping/HWRNG.pm

diff --git a/PVE/API2/Cluster/Mapping.pm b/PVE/API2/Cluster/Mapping.pm
index 40386579..d245cc01 100644
--- a/PVE/API2/Cluster/Mapping.pm
+++ b/PVE/API2/Cluster/Mapping.pm
@@ -3,11 +3,17 @@ package PVE::API2::Cluster::Mapping;
 use strict;
 use warnings;
 
+use PVE::API2::Cluster::Mapping::HWRNG;
 use PVE::API2::Cluster::Mapping::PCI;
 use PVE::API2::Cluster::Mapping::USB;
 
 use base qw(PVE::RESTHandler);
 
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::Cluster::Mapping::HWRNG",
+    path => 'hwrng',
+});
+
 __PACKAGE__->register_method ({
     subclass => "PVE::API2::Cluster::Mapping::PCI",
     path => 'pci',
@@ -41,6 +47,7 @@ __PACKAGE__->register_method ({
 	my ($param) = @_;
 
 	my $result = [
+	    { name => 'hwrng' },
 	    { name => 'pci' },
 	    { name => 'usb' },
 	];
diff --git a/PVE/API2/Cluster/Mapping/HWRNG.pm b/PVE/API2/Cluster/Mapping/HWRNG.pm
new file mode 100644
index 00000000..553c3ec6
--- /dev/null
+++ b/PVE/API2/Cluster/Mapping/HWRNG.pm
@@ -0,0 +1,286 @@
+package PVE::API2::Cluster::Mapping::HWRNG;
+
+use strict;
+use warnings;
+
+use Storable qw(dclone);
+
+use PVE::Mapping::HWRNG ();
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::Tools qw(extract_param);
+
+use base qw(PVE::RESTHandler);
+
+__PACKAGE__->register_method ({
+    name => 'index',
+    path => '',
+    method => 'GET',
+    # only proxy if we give the 'check-node' parameter
+    proxyto_callback => sub {
+	my ($rpcenv, $proxyto, $param) = @_;
+	return $param->{'check-node'} // 'localhost';
+    },
+    description => "List Hardware RNG Mappings",
+    permissions => {
+	description => "Only lists entries where you have 'Mapping.Modify', 'Mapping.Use' or".
+	    " 'Mapping.Audit' permissions on '/mapping/hwrng/<id>'.",
+	user => 'all',
+    },
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    'check-node' => get_standard_option('pve-node', {
+		description => "If given, checks the configurations on the given node for ".
+		    "correctness, and adds relevant errors to the devices.",
+		optional => 1,
+	    }),
+	},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => {
+		id => {
+		    type => 'string',
+		    description => "The logical ID of the mapping."
+		},
+		map => {
+		    type => 'array',
+		    description => "The entries of the mapping.",
+		    items => {
+			type => 'string',
+			description => "A mapping for a node.",
+		    },
+		},
+		description => {
+		    type => 'string',
+		    description => "A description of the logical mapping.",
+		},
+		error => {
+		    description => "A list of errors when 'check_node' is given.",
+		    items => {
+			type => 'object',
+			properties => {
+			    severity => {
+				type => "string",
+				description => "The severity of the error",
+			    },
+			    message => {
+				type => "string",
+				description => "The message of the error",
+			    },
+			},
+		    }
+		},
+	    },
+	},
+	links => [ { rel => 'child', href => "{id}" } ],
+    },
+    code => sub {
+	my ($param) = @_;
+
+	my $rpcenv = PVE::RPCEnvironment::get();
+	my $authuser = $rpcenv->get_user();
+	my $node = $param->{'check-node'};
+
+	die "Wrong node to check\n"
+	    if defined($node) && $node ne 'localhost' && $node ne PVE::INotify::nodename();
+
+	my $cfg = PVE::Mapping::HWRNG::config();
+
+	my $res = [];
+
+	my $privs = ['Mapping.Modify', 'Mapping.Use', 'Mapping.Audit'];
+
+	for my $id (keys $cfg->{ids}->%*) {
+	    next if !$rpcenv->check_full($authuser, "/mapping/hwrng/$id", $privs, 1, 1);
+	    next if !$cfg->{ids}->{$id};
+
+	    my $entry = dclone($cfg->{ids}->{$id});
+	    $entry->{id} = $id;
+	    $entry->{digest} = $cfg->{digest};
+
+	    if (defined($node)) {
+		$entry->{errors} = [];
+		if (my $mappings = PVE::Mapping::HWRNG::get_node_mapping($cfg, $id, $node)) {
+		    if (!scalar($mappings->@*)) {
+			push $entry->{errors}->@*, {
+			    severity => 'warning',
+			    message => "No mapping for node $node.",
+			};
+		    }
+		}
+	    }
+
+	    push @$res, $entry;
+	}
+
+	return $res;
+    },
+});
+
+__PACKAGE__->register_method ({
+    name => 'get',
+    protected => 1,
+    path => '{id}',
+    method => 'GET',
+    description => "Get Hardware RNG Mapping.",
+    permissions => {
+	check =>['or',
+	    ['perm', '/mapping/hwrng/{id}', ['Mapping.Audit']],
+	    ['perm', '/mapping/hwrng/{id}', ['Mapping.Use']],
+	    ['perm', '/mapping/hwrng/{id}', ['Mapping.Modify']],
+	],
+    },
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    id => {
+		type => 'string',
+		format => 'pve-configid',
+	    },
+	}
+    },
+    returns => { type => 'object' },
+    code => sub {
+	my ($param) = @_;
+
+	my $cfg = PVE::Mapping::HWRNG::config();
+	my $id = $param->{id};
+
+	my $entry = $cfg->{ids}->{$id};
+	die "mapping '$param->{id}' not found\n" if !defined($entry);
+
+	my $data = dclone($entry);
+
+	$data->{digest} = $cfg->{digest};
+
+	return $data;
+    },
+});
+
+__PACKAGE__->register_method ({
+    name => 'create',
+    protected => 1,
+    path => '',
+    method => 'POST',
+    description => "Create a new hardware RNG mapping.",
+    permissions => {
+	check => ['perm', '/mapping/hwrng', ['Mapping.Modify']],
+    },
+    parameters => PVE::Mapping::HWRNG->createSchema(1),
+    returns => {
+	type => 'null',
+    },
+    code => sub {
+	my ($param) = @_;
+
+	my $id = extract_param($param, 'id');
+
+	my $plugin = PVE::Mapping::HWRNG->lookup('hwrng');
+	my $opts = $plugin->check_config($id, $param, 1, 1);
+
+	PVE::Mapping::HWRNG::lock_hwrng_config(sub {
+	    my $cfg = PVE::Mapping::HWRNG::config();
+
+	    die "hwrng ID '$id' already defined\n" if defined($cfg->{ids}->{$id});
+
+	    $cfg->{ids}->{$id} = $opts;
+
+	    PVE::Mapping::HWRNG::write_hwrng_config($cfg);
+
+	}, "create hardware RNG mapping failed");
+
+	return;
+    },
+});
+
+__PACKAGE__->register_method ({
+    name => 'update',
+    protected => 1,
+    path => '{id}',
+    method => 'PUT',
+    description => "Update a Hardware RNG mapping.",
+    permissions => {
+	check => ['perm', '/mapping/hwrng/{id}', ['Mapping.Modify']],
+    },
+    parameters => PVE::Mapping::HWRNG->updateSchema(),
+    returns => {
+	type => 'null',
+    },
+    code => sub {
+	my ($param) = @_;
+
+	my $digest = extract_param($param, 'digest');
+	my $delete = extract_param($param, 'delete');
+	my $id = extract_param($param, 'id');
+
+	if ($delete) {
+	    $delete = [ PVE::Tools::split_list($delete) ];
+	}
+
+	PVE::Mapping::HWRNG::lock_hwrng_config(sub {
+	    my $cfg = PVE::Mapping::HWRNG::config();
+
+	    PVE::Tools::assert_if_modified($cfg->{digest}, $digest) if defined($digest);
+
+	    die "hwrng ID '$id' does not exist\n" if !defined($cfg->{ids}->{$id});
+
+	    my $plugin = PVE::Mapping::HWRNG->lookup('hwrng');
+	    my $opts = $plugin->check_config($id, $param, 1, 1);
+
+	    my $data = $cfg->{ids}->{$id};
+
+	    my $options = $plugin->private()->{options}->{hwrng};
+	    PVE::SectionConfig::delete_from_config($data, $options, $opts, $delete);
+
+	    $data->{$_} = $opts->{$_} for keys $opts->%*;
+
+	    PVE::Mapping::HWRNG::write_hwrng_config($cfg);
+	}, "update hardware RNG mapping failed");
+
+	return;
+    },
+});
+
+__PACKAGE__->register_method ({
+    name => 'delete',
+    protected => 1,
+    path => '{id}',
+    method => 'DELETE',
+    description => "Remove Hardware RNG Mapping.",
+    permissions => {
+	check => [ 'perm', '/mapping/hwrng', ['Mapping.Modify']],
+    },
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    id => {
+		type => 'string',
+		format => 'pve-configid',
+	    },
+	}
+    },
+    returns => { type => 'null' },
+    code => sub {
+	my ($param) = @_;
+
+	my $id = $param->{id};
+
+	PVE::Mapping::HWRNG::lock_hwrng_config(sub {
+	    my $cfg = PVE::Mapping::HWRNG::config();
+
+	    if ($cfg->{ids}->{$id}) {
+		delete $cfg->{ids}->{$id};
+	    }
+
+	    PVE::Mapping::HWRNG::write_hwrng_config($cfg);
+
+	}, "delete hardware RNG mapping failed");
+
+	return;
+    }
+});
+
+1;
diff --git a/PVE/API2/Cluster/Mapping/Makefile b/PVE/API2/Cluster/Mapping/Makefile
index e7345ab4..f53f97af 100644
--- a/PVE/API2/Cluster/Mapping/Makefile
+++ b/PVE/API2/Cluster/Mapping/Makefile
@@ -2,8 +2,9 @@ include ../../../../defines.mk
 
 # for node independent, cluster-wide applicable, API endpoints
 # ensure we do not conflict with files shipped by pve-cluster!!
-PERLSOURCE= 	\
-	PCI.pm	\
+PERLSOURCE= 		\
+	HWRNG.pm	\
+	PCI.pm		\
 	USB.pm
 
 all:
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [pve-devel] [PATCH manager v3 04/11] introduce hardware rng scanning api
  2025-02-10 15:37 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Filip Schauer
                   ` (2 preceding siblings ...)
  2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 03/11] introduce hardware rng mapping api Filip Schauer
@ 2025-02-10 15:37 ` Filip Schauer
  2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 05/11] ui: add hardware RNG resource mapping Filip Schauer
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Filip Schauer @ 2025-02-10 15:37 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 PVE/API2/Hardware.pm       |  7 ++++++
 PVE/API2/Hardware/HWRNG.pm | 47 ++++++++++++++++++++++++++++++++++++++
 PVE/API2/Hardware/Makefile |  1 +
 3 files changed, 55 insertions(+)
 create mode 100644 PVE/API2/Hardware/HWRNG.pm

diff --git a/PVE/API2/Hardware.pm b/PVE/API2/Hardware.pm
index 1c6fd8f5..02503b22 100644
--- a/PVE/API2/Hardware.pm
+++ b/PVE/API2/Hardware.pm
@@ -6,11 +6,17 @@ use warnings;
 use PVE::JSONSchema qw(get_standard_option);
 use PVE::RESTHandler;
 
+use PVE::API2::Hardware::HWRNG;
 use PVE::API2::Hardware::PCI;
 use PVE::API2::Hardware::USB;
 
 use base qw(PVE::RESTHandler);
 
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::Hardware::HWRNG",
+    path => 'hwrng',
+});
+
 __PACKAGE__->register_method ({
     subclass => "PVE::API2::Hardware::PCI",
     path => 'pci',
@@ -47,6 +53,7 @@ __PACKAGE__->register_method ({
 	my ($param) = @_;
 
 	my $res = [
+	    { type => 'hwrng' },
 	    { type => 'pci' },
 	    { type => 'usb' },
 	];
diff --git a/PVE/API2/Hardware/HWRNG.pm b/PVE/API2/Hardware/HWRNG.pm
new file mode 100644
index 00000000..1c3ac240
--- /dev/null
+++ b/PVE/API2/Hardware/HWRNG.pm
@@ -0,0 +1,47 @@
+package PVE::API2::Hardware::HWRNG;
+
+use strict;
+use warnings;
+
+use PVE::JSONSchema qw(get_standard_option);
+
+use PVE::QemuServer::RNG qw(check_rng_source);
+
+use base qw(PVE::RESTHandler);
+
+__PACKAGE__->register_method({
+    name => 'hwrngscan',
+    path => '',
+    method => 'GET',
+    description => "List local Hardware RNG devices.",
+    protected => 1,
+    proxyto => "node",
+    permissions => {
+	check => ['perm', '/', ['Sys.Audit']],
+    },
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    node => get_standard_option('pve-node'),
+	},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => {
+		path => { type => 'string'},
+	    },
+	},
+    },
+    code => sub {
+	my ($param) = @_;
+
+	eval { PVE::QemuServer::RNG::check_rng_source('/dev/hwrng') };
+	if (my $err = $@) {
+	    return [];
+	}
+
+	return [ { path => '/dev/hwrng' } ];
+    }
+});
diff --git a/PVE/API2/Hardware/Makefile b/PVE/API2/Hardware/Makefile
index 026a8dd6..1e552864 100644
--- a/PVE/API2/Hardware/Makefile
+++ b/PVE/API2/Hardware/Makefile
@@ -1,6 +1,7 @@
 include ../../../defines.mk
 
 PERLSOURCE=			\
+	HWRNG.pm		\
 	PCI.pm			\
 	USB.pm			\
 
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [pve-devel] [PATCH manager v3 05/11] ui: add hardware RNG resource mapping
  2025-02-10 15:37 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Filip Schauer
                   ` (3 preceding siblings ...)
  2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 04/11] introduce hardware rng scanning api Filip Schauer
@ 2025-02-10 15:37 ` Filip Schauer
  2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 06/11] ui: allow use of mapped hardware RNGs as entropy sources for VMs Filip Schauer
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Filip Schauer @ 2025-02-10 15:37 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 www/manager6/Makefile               |   2 +
 www/manager6/data/PermPathStore.js  |   1 +
 www/manager6/dc/Config.js           |  10 ++
 www/manager6/dc/HWRNGMapView.js     |  76 ++++++++++++++
 www/manager6/window/HWRNGMapEdit.js | 149 ++++++++++++++++++++++++++++
 5 files changed, 238 insertions(+)
 create mode 100644 www/manager6/dc/HWRNGMapView.js
 create mode 100644 www/manager6/window/HWRNGMapEdit.js

diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index c94a5cdf..01a95c7e 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -138,6 +138,7 @@ JSSRC= 							\
 	window/TreeSettingsEdit.js			\
 	window/PCIMapEdit.js				\
 	window/USBMapEdit.js				\
+	window/HWRNGMapEdit.js				\
 	window/GuestImport.js				\
 	ha/Fencing.js					\
 	ha/GroupEdit.js					\
@@ -188,6 +189,7 @@ JSSRC= 							\
 	dc/RealmSyncJob.js				\
 	dc/PCIMapView.js				\
 	dc/USBMapView.js				\
+	dc/HWRNGMapView.js				\
 	lxc/CmdMenu.js					\
 	lxc/Config.js					\
 	lxc/CreateWizard.js				\
diff --git a/www/manager6/data/PermPathStore.js b/www/manager6/data/PermPathStore.js
index 8785a1d7..8212b17d 100644
--- a/www/manager6/data/PermPathStore.js
+++ b/www/manager6/data/PermPathStore.js
@@ -10,6 +10,7 @@ Ext.define('PVE.data.PermPathStore', {
 	{ 'value': '/access/realm' },
 	{ 'value': '/mapping' },
 	{ 'value': '/mapping/notifications' },
+	{ 'value': '/mapping/hwrng' },
 	{ 'value': '/mapping/pci' },
 	{ 'value': '/mapping/usb' },
 	{ 'value': '/nodes' },
diff --git a/www/manager6/dc/Config.js b/www/manager6/dc/Config.js
index 74728c83..3650f290 100644
--- a/www/manager6/dc/Config.js
+++ b/www/manager6/dc/Config.js
@@ -329,6 +329,16 @@ Ext.define('PVE.dc.Config', {
 			    title: gettext('USB Devices'),
 			    flex: 1,
 			},
+			{
+			    xtype: 'splitter',
+			    collapsible: false,
+			    performCollapse: false,
+			},
+			{
+			    xtype: 'pveDcHWRNGMapView',
+			    title: gettext('Hardware RNG Devices'),
+			    flex: 1,
+			},
 		    ],
 		},
 	    );
diff --git a/www/manager6/dc/HWRNGMapView.js b/www/manager6/dc/HWRNGMapView.js
new file mode 100644
index 00000000..27c0d2fc
--- /dev/null
+++ b/www/manager6/dc/HWRNGMapView.js
@@ -0,0 +1,76 @@
+Ext.define('pve-resource-hwrng-tree', {
+    extend: 'Ext.data.Model',
+    idProperty: 'internalId',
+    fields: ['type', 'text', 'path', 'description', 'digest'],
+});
+
+Ext.define('PVE.dc.HWRNGMapView', {
+    extend: 'PVE.tree.ResourceMapTree',
+    alias: 'widget.pveDcHWRNGMapView',
+
+    editWindowClass: 'PVE.window.HWRNGMapEditWindow',
+    baseUrl: '/cluster/mapping/hwrng',
+    mapIconCls: 'pve-itype-icon-die',
+    getStatusCheckUrl: (node) => `/nodes/${node}/hardware/hwrng`,
+    entryIdProperty: 'path',
+
+    checkValidity: function(data, node) {
+	let me = this;
+	let paths = {};
+	data.forEach((entry) => {
+	    paths[entry.path] = entry;
+	});
+	me.getRootNode()?.cascade(function(rec) {
+	    if (rec.data.node !== node || rec.data.type !== 'map') {
+		return;
+	    }
+
+	    let device;
+	    if (rec.data.path) {
+		device = paths[rec.data.path];
+	    }
+
+	    if (!device) {
+		rec.set('valid', false);
+		rec.set(
+		    'errmsg',
+		    Ext.String.format(gettext("Cannot find Hardware RNG device {0}"), rec.data.id),
+		);
+		rec.commit();
+		return;
+	    }
+
+	    rec.set('valid', true);
+	    rec.commit();
+	});
+    },
+
+    store: {
+	sorters: 'text',
+	model: 'pve-resource-hwrng-tree',
+	data: {},
+    },
+
+    columns: [
+	{
+	    xtype: 'treecolumn',
+	    text: gettext('ID/Node/Path'),
+	    dataIndex: 'text',
+	    width: 200,
+	},
+	{
+	    header: gettext('Status'),
+	    dataIndex: 'valid',
+	    flex: 1,
+	    renderer: 'renderStatus',
+	},
+	{
+	    header: gettext('Comment'),
+	    dataIndex: 'description',
+	    renderer: function(value, _meta, record) {
+		return Ext.String.htmlEncode(value ?? record.data.comment);
+	    },
+	    flex: 1,
+	},
+    ],
+});
diff --git a/www/manager6/window/HWRNGMapEdit.js b/www/manager6/window/HWRNGMapEdit.js
new file mode 100644
index 00000000..aef4e2af
--- /dev/null
+++ b/www/manager6/window/HWRNGMapEdit.js
@@ -0,0 +1,149 @@
+Ext.define('PVE.window.HWRNGMapEditWindow', {
+    extend: 'Proxmox.window.Edit',
+    mixins: ['Proxmox.Mixin.CBind'],
+
+    width: 800,
+
+    subject: gettext('Hardware RNG mapping'),
+
+    onlineHelp: 'resource_mapping',
+
+    method: 'POST',
+
+    cbindData: function(initialConfig) {
+	let me = this;
+	me.isCreate = !me.name;
+	me.method = me.isCreate ? 'POST' : 'PUT';
+	me.hideMapping = !!me.entryOnly;
+	me.hideComment = me.name && !me.entryOnly;
+	me.hideNodeSelector = me.nodename || me.entryOnly;
+	me.hideNode = !me.nodename || !me.hideNodeSelector;
+	return {
+	    name: me.name,
+	    nodename: me.nodename,
+	};
+    },
+
+    submitUrl: function(_url, data) {
+	let me = this;
+	let name = me.isCreate ? '' : me.name;
+	return `/cluster/mapping/hwrng/${name}`;
+    },
+
+    controller: {
+	xclass: 'Ext.app.ViewController',
+
+	onGetValues: function(values) {
+	    let me = this;
+	    let view = me.getView();
+	    values.node ??= view.nodename;
+
+	    let name = values.name;
+	    let description = values.description;
+	    delete values.description;
+	    delete values.name;
+	    values.path = '/dev/hwrng';
+
+	    let map = [];
+	    if (me.originalMap) {
+		map = PVE.Parser.filterPropertyStringList(me.originalMap, (e) => e.node !== values.node);
+	    }
+	    if (view.isCreate) {
+		map.push(PVE.Parser.printPropertyString(values));
+	    }
+
+	    values = { map };
+	    if (description) {
+		values.description = description;
+	    }
+
+	    if (view.isCreate) {
+		values.id = name;
+	    }
+
+	    return values;
+	},
+
+	onSetValues: function(values) {
+	    let me = this;
+	    let view = me.getView();
+	    me.originalMap = [...values.map];
+	    let configuredNodes = [];
+	    PVE.Parser.filterPropertyStringList(values.map, (e) => {
+		configuredNodes.push(e.node);
+		if (e.node === view.nodename) {
+		    values = e;
+		}
+		return false;
+	    });
+
+	    me.lookup('nodeselector').disallowedNodes = configuredNodes;
+
+	    return values;
+	},
+    },
+
+    items: [
+	{
+	    xtype: 'inputpanel',
+	    onGetValues: function(values) {
+		return this.up('window').getController().onGetValues(values);
+	    },
+
+	    onSetValues: function(values) {
+		return this.up('window').getController().onSetValues(values);
+	    },
+
+	    column1: [
+		{
+		    xtype: 'pmxDisplayEditField',
+		    fieldLabel: gettext('Name'),
+		    cbind: {
+			editable: '{!name}',
+			value: '{name}',
+			submitValue: '{isCreate}',
+		    },
+		    name: 'name',
+		    allowBlank: false,
+		},
+		{
+		    xtype: 'displayfield',
+		    fieldLabel: gettext('Mapping on Node'),
+		    labelWidth: 120,
+		    name: 'node',
+		    cbind: {
+			value: '{nodename}',
+			disabled: '{hideNode}',
+			hidden: '{hideNode}',
+		    },
+		    allowBlank: false,
+		},
+		{
+		    xtype: 'pveNodeSelector',
+		    reference: 'nodeselector',
+		    fieldLabel: gettext('Mapping on Node'),
+		    labelWidth: 120,
+		    name: 'node',
+		    cbind: {
+			disabled: '{hideNodeSelector}',
+			hidden: '{hideNodeSelector}',
+		    },
+		    allowBlank: false,
+		},
+	    ],
+
+	    columnB: [
+		{
+		    xtype: 'proxmoxtextfield',
+		    fieldLabel: gettext('Comment'),
+		    submitValue: true,
+		    name: 'description',
+		    cbind: {
+			disabled: '{hideComment}',
+			hidden: '{hideComment}',
+		    },
+		},
+	    ],
+	},
+    ],
+});
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [pve-devel] [PATCH manager v3 06/11] ui: allow use of mapped hardware RNGs as entropy sources for VMs
  2025-02-10 15:37 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Filip Schauer
                   ` (4 preceding siblings ...)
  2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 05/11] ui: add hardware RNG resource mapping Filip Schauer
@ 2025-02-10 15:37 ` Filip Schauer
  2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 07/11] ui: split resource mapping types into tabbed views Filip Schauer
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Filip Schauer @ 2025-02-10 15:37 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 www/manager6/Makefile                 |  1 +
 www/manager6/form/HWRNGMapSelector.js | 99 +++++++++++++++++++++++++++
 www/manager6/qemu/HardwareView.js     |  9 ++-
 www/manager6/qemu/RNGEdit.js          | 79 ++++++++++++++-------
 4 files changed, 159 insertions(+), 29 deletions(-)
 create mode 100644 www/manager6/form/HWRNGMapSelector.js

diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 01a95c7e..d148a1c9 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -44,6 +44,7 @@ JSSRC= 							\
 	form/GuestIDSelector.js				\
 	form/HashAlgorithmSelector.js			\
 	form/HotplugFeatureSelector.js			\
+	form/HWRNGMapSelector.js			\
 	form/IPProtocolSelector.js			\
 	form/IPRefSelector.js				\
 	form/MDevSelector.js				\
diff --git a/www/manager6/form/HWRNGMapSelector.js b/www/manager6/form/HWRNGMapSelector.js
new file mode 100644
index 00000000..1c795d2d
--- /dev/null
+++ b/www/manager6/form/HWRNGMapSelector.js
@@ -0,0 +1,99 @@
+Ext.define('PVE.form.HWRNGMapSelector', {
+    extend: 'Proxmox.form.ComboGrid',
+    alias: 'widget.pveHWRNGMapSelector',
+
+    store: {
+	fields: ['name', 'path'],
+	filterOnLoad: true,
+	sorters: [
+	    {
+		property: 'name',
+		direction: 'ASC',
+	    },
+	],
+    },
+
+    allowBlank: false,
+    autoSelect: false,
+    displayField: 'id',
+    valueField: 'id',
+
+    listConfig: {
+	width: 800,
+	columns: [
+	    {
+		header: gettext('Name'),
+		dataIndex: 'id',
+		flex: 1,
+	    },
+	    {
+		header: gettext('Status'),
+		dataIndex: 'errors',
+		flex: 2,
+		renderer: function(value) {
+		    let me = this;
+
+		    if (!Ext.isArray(value) || !value?.length) {
+			return `<i class="fa fa-check-circle good"></i> ${gettext('Mapping matches host data')}`;
+		    }
+
+		    let errors = [];
+
+		    value.forEach((error) => {
+			let iconCls;
+			switch (error?.severity) {
+			    case 'warning':
+				iconCls = 'fa-exclamation-circle warning';
+				break;
+			    case 'error':
+				iconCls = 'fa-times-circle critical';
+				break;
+			}
+
+			let message = error?.message;
+			let icon = `<i class="fa ${iconCls}"></i>`;
+			if (iconCls !== undefined) {
+			    errors.push(`${icon} ${message}`);
+			}
+		    });
+
+		    return errors.join('<br>');
+		},
+	    },
+	    {
+		header: gettext('Comment'),
+		dataIndex: 'description',
+		flex: 1,
+		renderer: Ext.String.htmlEncode,
+	    },
+	],
+    },
+
+    setNodename: function(nodename) {
+	var me = this;
+
+	if (!nodename || me.nodename === nodename) {
+	    return;
+	}
+
+	me.nodename = nodename;
+
+	me.store.setProxy({
+	    type: 'proxmox',
+	    url: `/api2/json/cluster/mapping/hwrng?check-node=${nodename}`,
+	});
+
+	me.store.load();
+    },
+
+    initComponent: function() {
+	var me = this;
+
+	var nodename = me.nodename;
+	me.nodename = undefined;
+
+        me.callParent();
+
+	me.setNodename(nodename);
+    },
+});
diff --git a/www/manager6/qemu/HardwareView.js b/www/manager6/qemu/HardwareView.js
index c6d193fc..8085e288 100644
--- a/www/manager6/qemu/HardwareView.js
+++ b/www/manager6/qemu/HardwareView.js
@@ -315,8 +315,8 @@ Ext.define('PVE.qemu.HardwareView', {
 	rows.rng0 = {
 	    group: 45,
 	    tdCls: 'pve-itype-icon-die',
-	    editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.RNGEdit' : undefined,
-	    never_delete: !caps.nodes['Sys.Console'],
+	    editor: caps.vms['VM.Config.HWType'] || caps.mapping['Mapping.Use'] ? 'PVE.qemu.RNGEdit' : undefined,
+	    never_delete: !caps.vms['VM.Config.HWType'] && !caps.mapping['Mapping.Use'],
 	    header: gettext("VirtIO RNG"),
 	};
 
@@ -588,7 +588,6 @@ Ext.define('PVE.qemu.HardwareView', {
 	    });
 
 	    // heuristic only for disabling some stuff, the backend has the final word.
-	    const noSysConsolePerm = !caps.nodes['Sys.Console'];
 	    const noHWPerm = !caps.nodes['Sys.Console'] && !caps.mapping['Mapping.Use'];
 	    const noVMConfigHWTypePerm = !caps.vms['VM.Config.HWType'];
 	    const noVMConfigNetPerm = !caps.vms['VM.Config.Network'];
@@ -601,7 +600,7 @@ Ext.define('PVE.qemu.HardwareView', {
 	    me.down('#addAudio').setDisabled(noVMConfigHWTypePerm || isAtLimit('audio'));
 	    me.down('#addSerial').setDisabled(noVMConfigHWTypePerm || isAtLimit('serial'));
 	    me.down('#addNet').setDisabled(noVMConfigNetPerm || isAtLimit('net'));
-	    me.down('#addRng').setDisabled(noSysConsolePerm || isAtLimit('rng'));
+	    me.down('#addRng').setDisabled(noVMConfigHWTypePerm || isAtLimit('rng'));
 	    efidisk_menuitem.setDisabled(noVMConfigDiskPerm || isAtLimit('efidisk'));
 	    me.down('#addTpmState').setDisabled(noVMConfigDiskPerm || isAtLimit('tpmstate'));
 	    me.down('#addCloudinitDrive').setDisabled(noVMConfigCDROMPerm || noVMConfigCloudinitPerm || hasCloudInit);
@@ -745,7 +744,7 @@ Ext.define('PVE.qemu.HardwareView', {
 				text: gettext("VirtIO RNG"),
 				itemId: 'addRng',
 				iconCls: 'pve-itype-icon-die',
-				disabled: !caps.nodes['Sys.Console'],
+				disabled: !caps.vms['VM.Config.HWType'] && !caps.mapping['Mapping.Use'],
 				handler: editorFactory('RNGEdit'),
 			    },
 			],
diff --git a/www/manager6/qemu/RNGEdit.js b/www/manager6/qemu/RNGEdit.js
index e34e2c08..fab8c1b0 100644
--- a/www/manager6/qemu/RNGEdit.js
+++ b/www/manager6/qemu/RNGEdit.js
@@ -1,9 +1,19 @@
 Ext.define('PVE.qemu.RNGInputPanel', {
     extend: 'Proxmox.panel.InputPanel',
     xtype: 'pveRNGInputPanel',
+    mixins: ['Proxmox.Mixin.CBind'],
 
     onlineHelp: 'qm_virtio_rng',
 
+    cbindData: function(initialConfig) {
+	let me = this;
+	if (!me.pveSelNode) {
+	    throw "no pveSelNode given";
+	}
+
+	return { nodename: me.pveSelNode.data.node };
+    },
+
     onGetValues: function(values) {
 	if (values.max_bytes === "") {
 	    values.max_bytes = "0";
@@ -23,6 +33,10 @@ Ext.define('PVE.qemu.RNGInputPanel', {
 	    values.max_bytes = null;
 	}
 
+	if (values.mapping) {
+	    values.source = 'mapped';
+	}
+
 	this.callParent(arguments);
     },
 
@@ -35,27 +49,49 @@ Ext.define('PVE.qemu.RNGInputPanel', {
 		    limitWarning.setHidden(!!newVal);
 		},
 	    },
-	    '#source': {
-		change: function(el, newVal) {
-		    let limitWarning = this.lookupReference('sourceWarning');
-		    limitWarning.setHidden(newVal !== '/dev/random');
-		},
-	    },
 	},
     },
 
     items: [{
-	itemId: 'source',
-	name: 'source',
-	xtype: 'proxmoxKVComboBox',
-	value: '/dev/urandom',
-	fieldLabel: gettext('Entropy source'),
-	labelWidth: 130,
-	comboItems: [
-	    ['/dev/urandom', '/dev/urandom'],
-	    ['/dev/random', '/dev/random'],
-	    ['/dev/hwrng', '/dev/hwrng'],
-	],
+	xtype: 'fieldcontainer',
+	defaultType: 'radiofield',
+	layout: 'fit',
+	items: [{
+	    name: 'source',
+	    inputValue: '/dev/urandom',
+	    boxLabel: '/dev/urandom',
+	    checked: true,
+	},
+	{
+	    name: 'source',
+	    inputValue: '/dev/random',
+	    boxLabel: '/dev/random',
+	},
+	{
+	    name: 'source',
+	    inputValue: 'mapped',
+	    boxLabel: gettext('Use mapped Hardware RNG device'),
+	    reference: 'mapped',
+	    submitValue: false,
+	    listeners: {
+		change: function(f, value) {
+		    let me = this;
+		    if (!me.rendered) {
+			return;
+		    }
+		    me.up().down('field[name=mapping]').setDisabled(!value);
+		},
+	    },
+	},
+	{
+	    xtype: 'pveHWRNGMapSelector',
+	    name: 'mapping',
+	    cbind: { nodename: '{nodename}' },
+	    allowBlank: false,
+	    fieldLabel: gettext('Choose Device'),
+	    labelAlign: 'right',
+	    disabled: true,
+	}],
     },
     {
 	xtype: 'numberfield',
@@ -77,13 +113,6 @@ Ext.define('PVE.qemu.RNGInputPanel', {
 	labelWidth: 130,
 	emptyText: '1000',
     },
-    {
-	xtype: 'displayfield',
-	reference: 'sourceWarning',
-	value: gettext('Using /dev/random as entropy source is discouraged, as it can lead to host entropy starvation. /dev/urandom is preferred, and does not lead to a decrease in security in practice.'),
-	userCls: 'pmx-hint',
-	hidden: true,
-    },
     {
 	xtype: 'displayfield',
 	reference: 'limitWarning',
@@ -95,11 +124,13 @@ Ext.define('PVE.qemu.RNGInputPanel', {
 
 Ext.define('PVE.qemu.RNGEdit', {
     extend: 'Proxmox.window.Edit',
+    mixins: ['Proxmox.Mixin.CBind'],
 
     subject: gettext('VirtIO RNG'),
 
     items: [{
 	xtype: 'pveRNGInputPanel',
+	cbind: { pveSelNode: '{pveSelNode}' },
     }],
 
     initComponent: function() {
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [pve-devel] [PATCH manager v3 07/11] ui: split resource mapping types into tabbed views
  2025-02-10 15:37 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Filip Schauer
                   ` (5 preceding siblings ...)
  2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 06/11] ui: allow use of mapped hardware RNGs as entropy sources for VMs Filip Schauer
@ 2025-02-10 15:37 ` Filip Schauer
  2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 08/11] refactor: move rng related code into its own module Filip Schauer
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Filip Schauer @ 2025-02-10 15:37 UTC (permalink / raw)
  To: pve-devel

Reorganize resource mapping types into separate views accessible via
tabs.

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 www/manager6/Makefile                         | 13 ++---
 www/manager6/dc/Config.js                     | 51 +++----------------
 .../{window => resource-map}/HWRNGMapEdit.js  |  2 +-
 .../{dc => resource-map}/HWRNGMapView.js      |  4 +-
 .../{window => resource-map}/PCIMapEdit.js    |  2 +-
 .../{dc => resource-map}/PCIMapView.js        |  4 +-
 www/manager6/resource-map/ResourceMapView.js  | 23 +++++++++
 .../{window => resource-map}/USBMapEdit.js    |  2 +-
 .../{dc => resource-map}/USBMapView.js        |  4 +-
 9 files changed, 45 insertions(+), 60 deletions(-)
 rename www/manager6/{window => resource-map}/HWRNGMapEdit.js (98%)
 rename www/manager6/{dc => resource-map}/HWRNGMapView.js (93%)
 rename www/manager6/{window => resource-map}/PCIMapEdit.js (99%)
 rename www/manager6/{dc => resource-map}/PCIMapView.js (96%)
 create mode 100644 www/manager6/resource-map/ResourceMapView.js
 rename www/manager6/{window => resource-map}/USBMapEdit.js (99%)
 rename www/manager6/{dc => resource-map}/USBMapView.js (95%)

diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index d148a1c9..e13899b5 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -137,9 +137,6 @@ JSSRC= 							\
 	window/GuestDiskReassign.js				\
 	window/GuestStop.js				\
 	window/TreeSettingsEdit.js			\
-	window/PCIMapEdit.js				\
-	window/USBMapEdit.js				\
-	window/HWRNGMapEdit.js				\
 	window/GuestImport.js				\
 	ha/Fencing.js					\
 	ha/GroupEdit.js					\
@@ -188,9 +185,6 @@ JSSRC= 							\
 	dc/UserTagAccessEdit.js				\
 	dc/RegisteredTagsEdit.js			\
 	dc/RealmSyncJob.js				\
-	dc/PCIMapView.js				\
-	dc/USBMapView.js				\
-	dc/HWRNGMapView.js				\
 	lxc/CmdMenu.js					\
 	lxc/Config.js					\
 	lxc/CreateWizard.js				\
@@ -271,6 +265,13 @@ JSSRC= 							\
 	qemu/Smbios1Edit.js				\
 	qemu/SystemEdit.js				\
 	qemu/USBEdit.js					\
+	resource-map/PCIMapEdit.js			\
+	resource-map/USBMapEdit.js			\
+	resource-map/HWRNGMapEdit.js			\
+	resource-map/PCIMapView.js			\
+	resource-map/ResourceMapView.js			\
+	resource-map/USBMapView.js			\
+	resource-map/HWRNGMapView.js			\
 	sdn/Browser.js					\
 	sdn/ControllerView.js				\
 	sdn/Status.js					\
diff --git a/www/manager6/dc/Config.js b/www/manager6/dc/Config.js
index 3650f290..1dc82dee 100644
--- a/www/manager6/dc/Config.js
+++ b/www/manager6/dc/Config.js
@@ -297,51 +297,12 @@ Ext.define('PVE.dc.Config', {
 	if (caps.mapping['Mapping.Audit'] ||
 	    caps.mapping['Mapping.Use'] ||
 	    caps.mapping['Mapping.Modify']) {
-	    me.items.push(
-		{
-		    xtype: 'container',
-		    onlineHelp: 'resource_mapping',
-		    title: gettext('Resource Mappings'),
-		    itemId: 'resources',
-		    iconCls: 'fa fa-folder-o',
-		    layout: {
-			type: 'vbox',
-			align: 'stretch',
-			multi: true,
-		    },
-		    scrollable: true,
-		    defaults: {
-			border: false,
-		    },
-		    items: [
-			{
-			    xtype: 'pveDcPCIMapView',
-			    title: gettext('PCI Devices'),
-			    flex: 1,
-			},
-			{
-			    xtype: 'splitter',
-			    collapsible: false,
-			    performCollapse: false,
-			},
-			{
-			    xtype: 'pveDcUSBMapView',
-			    title: gettext('USB Devices'),
-			    flex: 1,
-			},
-			{
-			    xtype: 'splitter',
-			    collapsible: false,
-			    performCollapse: false,
-			},
-			{
-			    xtype: 'pveDcHWRNGMapView',
-			    title: gettext('Hardware RNG Devices'),
-			    flex: 1,
-			},
-		    ],
-		},
-	    );
+	    me.items.push({
+		xtype: 'pveResourceMapView',
+		title: gettext('Resource Mappings'),
+		itemId: 'resources',
+		iconCls: 'fa fa-folder-o',
+	    });
 	}
 
 	if (caps.mapping['Mapping.Audit'] ||
diff --git a/www/manager6/window/HWRNGMapEdit.js b/www/manager6/resource-map/HWRNGMapEdit.js
similarity index 98%
rename from www/manager6/window/HWRNGMapEdit.js
rename to www/manager6/resource-map/HWRNGMapEdit.js
index aef4e2af..a6ba0641 100644
--- a/www/manager6/window/HWRNGMapEdit.js
+++ b/www/manager6/resource-map/HWRNGMapEdit.js
@@ -1,4 +1,4 @@
-Ext.define('PVE.window.HWRNGMapEditWindow', {
+Ext.define('PVE.resource-map.HWRNGMapEditWindow', {
     extend: 'Proxmox.window.Edit',
     mixins: ['Proxmox.Mixin.CBind'],
 
diff --git a/www/manager6/dc/HWRNGMapView.js b/www/manager6/resource-map/HWRNGMapView.js
similarity index 93%
rename from www/manager6/dc/HWRNGMapView.js
rename to www/manager6/resource-map/HWRNGMapView.js
index 27c0d2fc..dbd96ea8 100644
--- a/www/manager6/dc/HWRNGMapView.js
+++ b/www/manager6/resource-map/HWRNGMapView.js
@@ -4,11 +4,11 @@ Ext.define('pve-resource-hwrng-tree', {
     fields: ['type', 'text', 'path', 'description', 'digest'],
 });
 
-Ext.define('PVE.dc.HWRNGMapView', {
+Ext.define('PVE.resource-map.HWRNGMapView', {
     extend: 'PVE.tree.ResourceMapTree',
     alias: 'widget.pveDcHWRNGMapView',
 
-    editWindowClass: 'PVE.window.HWRNGMapEditWindow',
+    editWindowClass: 'PVE.resource-map.HWRNGMapEditWindow',
     baseUrl: '/cluster/mapping/hwrng',
     mapIconCls: 'pve-itype-icon-die',
     getStatusCheckUrl: (node) => `/nodes/${node}/hardware/hwrng`,
diff --git a/www/manager6/window/PCIMapEdit.js b/www/manager6/resource-map/PCIMapEdit.js
similarity index 99%
rename from www/manager6/window/PCIMapEdit.js
rename to www/manager6/resource-map/PCIMapEdit.js
index faf58255..8146ebbd 100644
--- a/www/manager6/window/PCIMapEdit.js
+++ b/www/manager6/resource-map/PCIMapEdit.js
@@ -1,4 +1,4 @@
-Ext.define('PVE.window.PCIMapEditWindow', {
+Ext.define('PVE.resource-map.PCIMapEditWindow', {
     extend: 'Proxmox.window.Edit',
 
     mixins: ['Proxmox.Mixin.CBind'],
diff --git a/www/manager6/dc/PCIMapView.js b/www/manager6/resource-map/PCIMapView.js
similarity index 96%
rename from www/manager6/dc/PCIMapView.js
rename to www/manager6/resource-map/PCIMapView.js
index 80fe3c0f..c5b11f96 100644
--- a/www/manager6/dc/PCIMapView.js
+++ b/www/manager6/resource-map/PCIMapView.js
@@ -4,11 +4,11 @@ Ext.define('pve-resource-pci-tree', {
     fields: ['type', 'text', 'path', 'id', 'subsystem-id', 'iommugroup', 'description', 'digest'],
 });
 
-Ext.define('PVE.dc.PCIMapView', {
+Ext.define('PVE.resource-map.PCIMapView', {
     extend: 'PVE.tree.ResourceMapTree',
     alias: 'widget.pveDcPCIMapView',
 
-    editWindowClass: 'PVE.window.PCIMapEditWindow',
+    editWindowClass: 'PVE.resource-map.PCIMapEditWindow',
     baseUrl: '/cluster/mapping/pci',
     mapIconCls: 'pve-itype-icon-pci',
     getStatusCheckUrl: (node) => `/nodes/${node}/hardware/pci?pci-class-blacklist=`,
diff --git a/www/manager6/resource-map/ResourceMapView.js b/www/manager6/resource-map/ResourceMapView.js
new file mode 100644
index 00000000..dcf2cc2d
--- /dev/null
+++ b/www/manager6/resource-map/ResourceMapView.js
@@ -0,0 +1,23 @@
+Ext.define('PVE.resource-map.ResourceMapView', {
+    extend: 'Ext.tab.Panel',
+    alias: 'widget.pveResourceMapView',
+    online_help: 'resource_mapping',
+
+    items: [
+	{
+	    xtype: 'pveDcPCIMapView',
+	    title: gettext('PCI Devices'),
+	    itemId: 'pci-map',
+	},
+	{
+	    xtype: 'pveDcUSBMapView',
+	    title: gettext('USB Devices'),
+	    itemId: 'usb-map',
+	},
+	{
+	    xtype: 'pveDcHWRNGMapView',
+	    title: gettext('Hardware RNG Devices'),
+	    itemId: 'hwrng-map',
+	},
+    ],
+});
diff --git a/www/manager6/window/USBMapEdit.js b/www/manager6/resource-map/USBMapEdit.js
similarity index 99%
rename from www/manager6/window/USBMapEdit.js
rename to www/manager6/resource-map/USBMapEdit.js
index 69a40026..6af0ad07 100644
--- a/www/manager6/window/USBMapEdit.js
+++ b/www/manager6/resource-map/USBMapEdit.js
@@ -1,4 +1,4 @@
-Ext.define('PVE.window.USBMapEditWindow', {
+Ext.define('PVE.resource-map.USBMapEditWindow', {
     extend: 'Proxmox.window.Edit',
 
     mixins: ['Proxmox.Mixin.CBind'],
diff --git a/www/manager6/dc/USBMapView.js b/www/manager6/resource-map/USBMapView.js
similarity index 95%
rename from www/manager6/dc/USBMapView.js
rename to www/manager6/resource-map/USBMapView.js
index 96edc587..551f9472 100644
--- a/www/manager6/dc/USBMapView.js
+++ b/www/manager6/resource-map/USBMapView.js
@@ -4,11 +4,11 @@ Ext.define('pve-resource-usb-tree', {
     fields: ['type', 'text', 'path', 'id', 'description', 'digest'],
 });
 
-Ext.define('PVE.dc.USBMapView', {
+Ext.define('PVE.resource-map.USBMapView', {
     extend: 'PVE.tree.ResourceMapTree',
     alias: 'widget.pveDcUSBMapView',
 
-    editWindowClass: 'PVE.window.USBMapEditWindow',
+    editWindowClass: 'PVE.resource-map.USBMapEditWindow',
     baseUrl: '/cluster/mapping/usb',
     mapIconCls: 'fa fa-usb',
     getStatusCheckUrl: (node) => `/nodes/${node}/hardware/usb`,
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [pve-devel] [PATCH qemu-server v3 08/11] refactor: move rng related code into its own module
  2025-02-10 15:37 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Filip Schauer
                   ` (6 preceding siblings ...)
  2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 07/11] ui: split resource mapping types into tabbed views Filip Schauer
@ 2025-02-10 15:37 ` Filip Schauer
  2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 09/11] add helpers for VirtIO RNG command line arguments Filip Schauer
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Filip Schauer @ 2025-02-10 15:37 UTC (permalink / raw)
  To: pve-devel

Move code related to VirtIO RNG configuration for a VM to its own
module.

Also remove mentions about entropy-starvation when using /dev/random as
the entropy source from the descriptions of the rng parameters. This
concern no longer applies since the removal of the blocking entropy pool
in kernel version 5.6. [1] [2]

[1] https://git.kernel.org/torvalds/c/acd77500aa8a337baa6d853568c4b55aca48e20f
[2] https://lwn.net/Articles/808575/

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 PVE/QemuServer.pm       | 63 +-----------------------------
 PVE/QemuServer/Makefile |  1 +
 PVE/QemuServer/RNG.pm   | 86 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 89 insertions(+), 61 deletions(-)
 create mode 100644 PVE/QemuServer/RNG.pm

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 808c0e1c..09d2b3a8 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -60,6 +60,7 @@ use PVE::QemuServer::MetaInfo;
 use PVE::QemuServer::Monitor qw(mon_cmd);
 use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr print_pcie_root_port parse_hostpci);
 use PVE::QemuServer::QMPHelpers qw(qemu_deviceadd qemu_devicedel qemu_objectadd qemu_objectdel);
+use PVE::QemuServer::RNG qw(check_rng_source parse_rng);
 use PVE::QemuServer::USB;
 
 my $have_sdn;
@@ -248,39 +249,6 @@ my $spice_enhancements_fmt = {
     },
 };
 
-my $rng_fmt = {
-    source => {
-	type => 'string',
-	enum => ['/dev/urandom', '/dev/random', '/dev/hwrng'],
-	default_key => 1,
-	description => "The file on the host to gather entropy from. In most cases '/dev/urandom'"
-	    ." should be preferred over '/dev/random' to avoid entropy-starvation issues on the"
-	    ." host. Using urandom does *not* decrease security in any meaningful way, as it's"
-	    ." still seeded from real entropy, and the bytes provided will most likely be mixed"
-	    ." with real entropy on the guest as well. '/dev/hwrng' can be used to pass through"
-	    ." a hardware RNG from the host.",
-    },
-    max_bytes => {
-	type => 'integer',
-	description => "Maximum bytes of entropy allowed to get injected into the guest every"
-	    ." 'period' milliseconds. Prefer a lower value when using '/dev/random' as source. Use"
-	    ." `0` to disable limiting (potentially dangerous!).",
-	optional => 1,
-
-	# default is 1 KiB/s, provides enough entropy to the guest to avoid boot-starvation issues
-	# (e.g. systemd etc...) while allowing no chance of overwhelming the host, provided we're
-	# reading from /dev/urandom
-	default => 1024,
-    },
-    period => {
-	type => 'integer',
-	description => "Every 'period' milliseconds the entropy-injection quota is reset, allowing"
-	    ." the guest to retrieve another 'max_bytes' of entropy.",
-	optional => 1,
-	default => 1000,
-    },
-};
-
 my $confdesc = {
     onboot => {
 	optional => 1,
@@ -708,7 +676,7 @@ EODESCR
     },
     rng0 => {
 	type => 'string',
-	format => $rng_fmt,
+	format => 'pve-qm-rng',
 	description => "Configure a VirtIO-based Random Number Generator.",
 	optional => 1,
     },
@@ -1971,16 +1939,6 @@ sub parse_vga {
     return $res;
 }
 
-sub parse_rng {
-    my ($value) = @_;
-
-    return if !$value;
-
-    my $res = eval { parse_property_string($rng_fmt, $value) };
-    warn $@ if $@;
-    return $res;
-}
-
 sub qemu_created_version_fixups {
     my ($conf, $forcemachine, $kvmver) = @_;
 
@@ -4020,23 +3978,6 @@ sub config_to_command {
     return wantarray ? ($cmd, $vollist, $spice_port, $pci_devices) : $cmd;
 }
 
-sub check_rng_source {
-    my ($source) = @_;
-
-    # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
-    die "cannot create VirtIO RNG device: source file '$source' doesn't exist\n"
-	if ! -e $source;
-
-    my $rng_current = '/sys/devices/virtual/misc/hw_random/rng_current';
-    if ($source eq '/dev/hwrng' && file_read_firstline($rng_current) eq 'none') {
-	# Needs to abort, otherwise QEMU crashes on first rng access. Note that rng_current cannot
-	# be changed to 'none' manually, so once the VM is past this point, it's no longer an issue.
-	die "Cannot start VM with passed-through RNG device: '/dev/hwrng' exists, but"
-	    ." '$rng_current' is set to 'none'. Ensure that a compatible hardware-RNG is attached"
-	    ." to the host.\n";
-    }
-}
-
 sub spice_port {
     my ($vmid) = @_;
 
diff --git a/PVE/QemuServer/Makefile b/PVE/QemuServer/Makefile
index 18fd13ea..83c6af79 100644
--- a/PVE/QemuServer/Makefile
+++ b/PVE/QemuServer/Makefile
@@ -1,4 +1,5 @@
 SOURCES=PCI.pm		\
+	RNG.pm		\
 	USB.pm		\
 	Memory.pm	\
 	ImportDisk.pm	\
diff --git a/PVE/QemuServer/RNG.pm b/PVE/QemuServer/RNG.pm
new file mode 100644
index 00000000..22d1e9cc
--- /dev/null
+++ b/PVE/QemuServer/RNG.pm
@@ -0,0 +1,86 @@
+package PVE::QemuServer::RNG;
+
+use strict;
+use warnings;
+
+use PVE::JSONSchema;
+use PVE::Tools qw(file_read_firstline);
+
+use PVE::QemuServer::PCI qw(print_pci_addr);
+
+use base 'Exporter';
+
+our @EXPORT_OK = qw(
+parse_rng
+check_rng_source
+);
+
+my $rng_fmt = {
+    source => {
+	type => 'string',
+	enum => ['/dev/urandom', '/dev/random', '/dev/hwrng'],
+	default_key => 1,
+	description => "The file on the host to gather entropy from. Using urandom does *not*"
+	    ." decrease security in any meaningful way, as it's still seeded from real entropy, and"
+	    ." the bytes provided will most likely be mixed with real entropy on the guest as well."
+	    ." '/dev/hwrng' can be used to pass through a hardware RNG from the host.",
+    },
+    max_bytes => {
+	type => 'integer',
+	description => "Maximum bytes of entropy allowed to get injected into the guest every"
+	    ." 'period' milliseconds. Use `0` to disable limiting (potentially dangerous!).",
+	optional => 1,
+
+	# default is 1 KiB/s, provides enough entropy to the guest to avoid boot-starvation issues
+	# (e.g. systemd etc...) while allowing no chance of overwhelming the host, provided we're
+	# reading from /dev/urandom
+	default => 1024,
+    },
+    period => {
+	type => 'integer',
+	description => "Every 'period' milliseconds the entropy-injection quota is reset, allowing"
+	    ." the guest to retrieve another 'max_bytes' of entropy.",
+	optional => 1,
+	default => 1000,
+    },
+};
+
+PVE::JSONSchema::register_format('pve-qm-rng', $rng_fmt);
+
+our $rngdesc = {
+    type => 'string',
+    format => $rng_fmt,
+    optional => 1,
+    description => "Configure a VirtIO-based Random Number Generator.",
+};
+PVE::JSONSchema::register_standard_option('pve-qm-rng', $rngdesc);
+
+sub parse_rng {
+    my ($value) = @_;
+
+    return if !$value;
+
+    my $res = eval { PVE::JSONSchema::parse_property_string($rng_fmt, $value) };
+    warn $@ if $@;
+
+    return $res;
+}
+
+sub check_rng_source {
+    my ($source) = @_;
+
+    # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
+    die "cannot create VirtIO RNG device: source file '$source' doesn't exist\n"
+	if ! -e $source;
+
+    my $rng_current = '/sys/devices/virtual/misc/hw_random/rng_current';
+    if ($source eq '/dev/hwrng' && file_read_firstline($rng_current) eq 'none') {
+	# Needs to abort, otherwise QEMU crashes on first rng access. Note that rng_current cannot
+	# be changed to 'none' manually, so once the VM is past this point, it's no longer an issue.
+	die "Cannot start VM with passed-through RNG device: '/dev/hwrng' exists, but"
+	    ." '$rng_current' is set to 'none'. Ensure that a compatible hardware-RNG is attached"
+	    ." to the host.\n";
+    }
+}
+
+1;
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [pve-devel] [PATCH qemu-server v3 09/11] add helpers for VirtIO RNG command line arguments
  2025-02-10 15:37 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Filip Schauer
                   ` (7 preceding siblings ...)
  2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 08/11] refactor: move rng related code into its own module Filip Schauer
@ 2025-02-10 15:37 ` Filip Schauer
  2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 10/11] allow non-root users to set /dev/u?random as an RNG source Filip Schauer
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Filip Schauer @ 2025-02-10 15:37 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 PVE/QemuServer.pm     | 18 +++++-------------
 PVE/QemuServer/RNG.pm | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 13 deletions(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 09d2b3a8..70518924 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -60,7 +60,7 @@ use PVE::QemuServer::MetaInfo;
 use PVE::QemuServer::Monitor qw(mon_cmd);
 use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr print_pcie_root_port parse_hostpci);
 use PVE::QemuServer::QMPHelpers qw(qemu_deviceadd qemu_devicedel qemu_objectadd qemu_objectdel);
-use PVE::QemuServer::RNG qw(check_rng_source parse_rng);
+use PVE::QemuServer::RNG qw(parse_rng print_rng_device_commandline print_rng_object_commandline);
 use PVE::QemuServer::USB;
 
 my $have_sdn;
@@ -3685,18 +3685,10 @@ sub config_to_command {
 
     my $rng = $conf->{rng0} ? parse_rng($conf->{rng0}) : undef;
     if ($rng && $version_guard->(4, 1, 2)) {
-	check_rng_source($rng->{source});
-
-	my $max_bytes = $rng->{max_bytes} // $rng_fmt->{max_bytes}->{default};
-	my $period = $rng->{period} // $rng_fmt->{period}->{default};
-	my $limiter_str = "";
-	if ($max_bytes) {
-	    $limiter_str = ",max-bytes=$max_bytes,period=$period";
-	}
-
-	my $rng_addr = print_pci_addr("rng0", $bridges, $arch, $machine_type);
-	push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
-	push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
+	my $rng_object = print_rng_object_commandline('rng0', $rng);
+	my $rng_device = print_rng_device_commandline('rng0', $rng, $bridges, $arch, $machine_type);
+	push @$devices, '-object', $rng_object;
+	push @$devices, '-device', $rng_device;
     }
 
     my $spice_port;
diff --git a/PVE/QemuServer/RNG.pm b/PVE/QemuServer/RNG.pm
index 22d1e9cc..ae5b2530 100644
--- a/PVE/QemuServer/RNG.pm
+++ b/PVE/QemuServer/RNG.pm
@@ -13,6 +13,8 @@ use base 'Exporter';
 our @EXPORT_OK = qw(
 parse_rng
 check_rng_source
+print_rng_device_commandline
+print_rng_object_commandline
 );
 
 my $rng_fmt = {
@@ -83,4 +85,44 @@ sub check_rng_source {
     }
 }
 
+sub get_rng_source_path {
+    my ($rng) = @_;
+
+    my $source = $rng->{source};
+
+    if (defined($source)) {
+	return $source;
+    }
+
+    return;
+}
+
+sub print_rng_device_commandline {
+    my ($id, $rng, $bridges, $arch, $machine) = @_;
+
+    die "no rng device specified\n" if !$rng;
+
+    my $max_bytes = $rng->{max_bytes} // $rng_fmt->{max_bytes}->{default};
+    my $period = $rng->{period} // $rng_fmt->{period}->{default};
+    my $limiter_str = "";
+    if ($max_bytes) {
+	$limiter_str = ",max-bytes=$max_bytes,period=$period";
+    }
+
+    my $rng_addr = print_pci_addr($id, $bridges, $arch, $machine);
+
+    return "virtio-rng-pci,rng=$id$limiter_str$rng_addr";
+}
+
+sub print_rng_object_commandline {
+    my ($id, $rng) = @_;
+
+    die "no rng device specified\n" if !$rng;
+
+    my $source_path = get_rng_source_path($rng);
+    check_rng_source($source_path);
+
+    return "rng-random,filename=$source_path,id=$id";
+}
+
 1;
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [pve-devel] [PATCH qemu-server v3 10/11] allow non-root users to set /dev/u?random as an RNG source
  2025-02-10 15:37 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Filip Schauer
                   ` (8 preceding siblings ...)
  2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 09/11] add helpers for VirtIO RNG command line arguments Filip Schauer
@ 2025-02-10 15:37 ` Filip Schauer
  2025-02-11 12:34   ` Fabian Grünbichler
  2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 11/11] let VirtIO RNG devices source entropy from mapped HWRNGs Filip Schauer
  2025-02-11 12:34 ` [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Fabian Grünbichler
  11 siblings, 1 reply; 16+ messages in thread
From: Filip Schauer @ 2025-02-10 15:37 UTC (permalink / raw)
  To: pve-devel

Allow non-root users with the VM.Config.HWType privilege to configure
/dev/urandom & /dev/random as an entropy source for a VirtIO RNG device.
/dev/hwrng remains restricted to the root user.

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 PVE/API2/Qemu.pm  | 43 +++++++++++++++++++++++++++++++++++++++++++
 PVE/QemuServer.pm | 13 +++++++++++--
 2 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 295260e7..194e6357 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -38,6 +38,7 @@ use PVE::QemuServer::Memory qw(get_current_memory);
 use PVE::QemuServer::MetaInfo;
 use PVE::QemuServer::PCI;
 use PVE::QemuServer::QMPHelpers;
+use PVE::QemuServer::RNG;
 use PVE::QemuServer::USB;
 use PVE::QemuMigrate;
 use PVE::RPCEnvironment;
@@ -673,6 +674,7 @@ my $hwtypeoptions = {
     'vga' => 1,
     'watchdog' => 1,
     'audio0' => 1,
+    'rng0' => 1,
 };
 
 my $generaloptions = {
@@ -801,6 +803,36 @@ my sub check_vm_create_hostpci_perm {
     return 1;
 };
 
+my sub check_rng_perm {
+    my ($rpcenv, $authuser, $vmid, $pool, $opt, $value) = @_;
+
+    return 1 if $authuser eq 'root@pam';
+
+    $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.HWType']);
+
+    my $device = PVE::JSONSchema::parse_property_string('pve-qm-rng', $value);
+    if ($device->{source}) {
+	if ($device->{source} eq '/dev/hwrng') {
+	    die "only root can set '$opt' config for a non-mapped Hardware RNG device\n";
+	}
+    }
+
+    return 1;
+}
+
+my sub check_vm_create_rng_perm {
+    my ($rpcenv, $authuser, $vmid, $pool, $param) = @_;
+
+    return 1 if $authuser eq 'root@pam';
+
+    foreach my $opt (keys %{$param}) {
+	next if $opt !~ m/^rng\d+$/;
+	check_rng_perm($rpcenv, $authuser, $vmid, $pool, $opt, $param->{$opt});
+    }
+
+    return 1;
+};
+
 my $check_vm_modify_config_perm = sub {
     my ($rpcenv, $authuser, $vmid, $pool, $key_list) = @_;
 
@@ -1114,6 +1146,7 @@ __PACKAGE__->register_method({
 	    &$check_vm_create_serial_perm($rpcenv, $authuser, $vmid, $pool, $param);
 	    check_vm_create_usb_perm($rpcenv, $authuser, $vmid, $pool, $param);
 	    check_vm_create_hostpci_perm($rpcenv, $authuser, $vmid, $pool, $param);
+	    check_vm_create_rng_perm($rpcenv, $authuser, $vmid, $pool, $param);
 
 	    PVE::QemuServer::check_bridge_access($rpcenv, $authuser, $param);
 	    &$check_cpu_model_access($rpcenv, $authuser, $param);
@@ -2005,6 +2038,10 @@ my $update_vm_api  = sub {
 		    check_hostpci_perm($rpcenv, $authuser, $vmid, undef, $opt, $val);
 		    PVE::QemuConfig->add_to_pending_delete($conf, $opt, $force);
 		    PVE::QemuConfig->write_config($vmid, $conf);
+		} elsif ($opt eq m/^rng\d+$/) {
+		    check_rng_perm($rpcenv, $authuser, $vmid, undef, $opt, $val);
+		    PVE::QemuConfig->add_to_pending_delete($conf, $opt, $force);
+		    PVE::QemuConfig->write_config($vmid, $conf);
 		} elsif ($opt eq 'tags') {
 		    assert_tag_permissions($vmid, $val, '', $rpcenv, $authuser);
 		    delete $conf->{$opt};
@@ -2095,6 +2132,12 @@ my $update_vm_api  = sub {
 		    }
 		    check_hostpci_perm($rpcenv, $authuser, $vmid, undef, $opt, $param->{$opt});
 		    $conf->{pending}->{$opt} = $param->{$opt};
+		} elsif ($opt =~ m/^rng\d+$/) {
+		    if (my $oldvalue = $conf->{$opt}) {
+			check_rng_perm($rpcenv, $authuser, $vmid, undef, $opt, $oldvalue);
+		    }
+		    check_rng_perm($rpcenv, $authuser, $vmid, undef, $opt, $param->{$opt});
+		    $conf->{pending}->{$opt} = $param->{$opt};
 		} elsif ($opt eq 'tags') {
 		    assert_tag_permissions($vmid, $conf->{$opt}, $param->{$opt}, $rpcenv, $authuser);
 		    $conf->{pending}->{$opt} = PVE::GuestHelpers::get_unique_tags($param->{$opt});
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 70518924..cc69eeb1 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -6398,8 +6398,17 @@ sub check_mapping_access {
 	    } else {
 		die "either 'host' or 'mapping' must be set.\n";
 	    }
-       }
-   }
+	} elsif ($opt =~ m/^rng\d+$/) {
+	    my $device = PVE::JSONSchema::parse_property_string('pve-qm-rng', $conf->{$opt});
+
+	    if ($device->{source}) {
+		if ($device->{source} eq '/dev/hwrng') {
+		    die "only root can set '$opt' config for a non-mapped Hardware RNG device\n"
+			if $user ne 'root@pam';
+		}
+	    }
+	}
+    }
 };
 
 sub check_restore_permissions {
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [pve-devel] [PATCH qemu-server v3 11/11] let VirtIO RNG devices source entropy from mapped HWRNGs
  2025-02-10 15:37 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Filip Schauer
                   ` (9 preceding siblings ...)
  2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 10/11] allow non-root users to set /dev/u?random as an RNG source Filip Schauer
@ 2025-02-10 15:37 ` Filip Schauer
  2025-02-11 12:34   ` Fabian Grünbichler
  2025-02-11 12:34 ` [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Fabian Grünbichler
  11 siblings, 1 reply; 16+ messages in thread
From: Filip Schauer @ 2025-02-10 15:37 UTC (permalink / raw)
  To: pve-devel

This allows a user with the Mapping.Modify privilege on /mapping/hwrng
to configure a hardware RNG mapping. A less privileged user with the
Mapping.Use privilege can then pass the mapped hardware RNG device as an
entropy source to a VirtIO RNG device.

Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
 PVE/API2/Qemu.pm      |  5 +++++
 PVE/QemuServer.pm     |  5 +++++
 PVE/QemuServer/RNG.pm | 25 +++++++++++++++++++++++++
 3 files changed, 35 insertions(+)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 194e6357..33b3625b 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -812,9 +812,14 @@ my sub check_rng_perm {
 
     my $device = PVE::JSONSchema::parse_property_string('pve-qm-rng', $value);
     if ($device->{source}) {
+	# Backward compatibility for non-mapped /dev/hwrng
 	if ($device->{source} eq '/dev/hwrng') {
 	    die "only root can set '$opt' config for a non-mapped Hardware RNG device\n";
 	}
+    } elsif ($device->{mapping}) {
+	$rpcenv->check_full($authuser, "/mapping/hwrng/$device->{mapping}", ['Mapping.Use']);
+    } else {
+	die "either 'source' or 'mapping' must be set.\n";
     }
 
     return 1;
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index cc69eeb1..82a6c65d 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -6402,10 +6402,15 @@ sub check_mapping_access {
 	    my $device = PVE::JSONSchema::parse_property_string('pve-qm-rng', $conf->{$opt});
 
 	    if ($device->{source}) {
+		# Backward compatibility for non-mapped /dev/hwrng
 		if ($device->{source} eq '/dev/hwrng') {
 		    die "only root can set '$opt' config for a non-mapped Hardware RNG device\n"
 			if $user ne 'root@pam';
 		}
+	    } elsif ($device->{mapping}) {
+		$rpcenv->check_full($user, "/mapping/hwrng/$device->{mapping}", ['Mapping.Use']);
+	    } else {
+		die "either 'source' or 'mapping' must be set.\n";
 	    }
 	}
     }
diff --git a/PVE/QemuServer/RNG.pm b/PVE/QemuServer/RNG.pm
index ae5b2530..3ee19852 100644
--- a/PVE/QemuServer/RNG.pm
+++ b/PVE/QemuServer/RNG.pm
@@ -4,6 +4,7 @@ use strict;
 use warnings;
 
 use PVE::JSONSchema;
+use PVE::Mapping::HWRNG;
 use PVE::Tools qw(file_read_firstline);
 
 use PVE::QemuServer::PCI qw(print_pci_addr);
@@ -22,11 +23,20 @@ my $rng_fmt = {
 	type => 'string',
 	enum => ['/dev/urandom', '/dev/random', '/dev/hwrng'],
 	default_key => 1,
+	optional => 1,
 	description => "The file on the host to gather entropy from. Using urandom does *not*"
 	    ." decrease security in any meaningful way, as it's still seeded from real entropy, and"
 	    ." the bytes provided will most likely be mixed with real entropy on the guest as well."
 	    ." '/dev/hwrng' can be used to pass through a hardware RNG from the host.",
     },
+    mapping => {
+	optional => 1,
+	type => 'string',
+	format_description => 'mapping-id',
+	format => 'pve-configid',
+	description => "The ID of a cluster wide mapping. When specified, entropy is gathered from"
+	    ." a hardware RNG on the host. Either this or the default-key 'source' must be set.",
+    },
     max_bytes => {
 	type => 'integer',
 	description => "Maximum bytes of entropy allowed to get injected into the guest every"
@@ -65,6 +75,11 @@ sub parse_rng {
     my $res = eval { PVE::JSONSchema::parse_property_string($rng_fmt, $value) };
     warn $@ if $@;
 
+    my $source = $res->{source};
+    my $mapping = $res->{mapping};
+
+    return if $source && $mapping; # not a valid configuration
+
     return $res;
 }
 
@@ -89,9 +104,19 @@ sub get_rng_source_path {
     my ($rng) = @_;
 
     my $source = $rng->{source};
+    my $mapping = $rng->{mapping};
+
+    return if $source && $mapping; # not a valid configuration
 
     if (defined($source)) {
 	return $source;
+    } elsif (defined($mapping)) {
+	my $devices = PVE::Mapping::HWRNG::find_on_current_node($mapping);
+	die "Hardware RNG mapping not found for '$mapping'\n" if !$devices || !scalar($devices->@*);
+	die "More than one Hardware RNG mapping per host not supported\n"
+	    if scalar($devices->@*) > 1;
+
+	return $devices->[0]->{path};
     }
 
     return;
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [pve-devel] [PATCH qemu-server v3 10/11] allow non-root users to set /dev/u?random as an RNG source
  2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 10/11] allow non-root users to set /dev/u?random as an RNG source Filip Schauer
@ 2025-02-11 12:34   ` Fabian Grünbichler
  0 siblings, 0 replies; 16+ messages in thread
From: Fabian Grünbichler @ 2025-02-11 12:34 UTC (permalink / raw)
  To: Proxmox VE development discussion

On February 10, 2025 4:37 pm, Filip Schauer wrote:
> Allow non-root users with the VM.Config.HWType privilege to configure
> /dev/urandom & /dev/random as an entropy source for a VirtIO RNG device.
> /dev/hwrng remains restricted to the root user.
> 
> Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
> ---
>  PVE/API2/Qemu.pm  | 43 +++++++++++++++++++++++++++++++++++++++++++
>  PVE/QemuServer.pm | 13 +++++++++++--
>  2 files changed, 54 insertions(+), 2 deletions(-)
> 
> diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
> index 295260e7..194e6357 100644
> --- a/PVE/API2/Qemu.pm
> +++ b/PVE/API2/Qemu.pm
> @@ -38,6 +38,7 @@ use PVE::QemuServer::Memory qw(get_current_memory);
>  use PVE::QemuServer::MetaInfo;
>  use PVE::QemuServer::PCI;
>  use PVE::QemuServer::QMPHelpers;
> +use PVE::QemuServer::RNG;
>  use PVE::QemuServer::USB;
>  use PVE::QemuMigrate;
>  use PVE::RPCEnvironment;
> @@ -673,6 +674,7 @@ my $hwtypeoptions = {
>      'vga' => 1,
>      'watchdog' => 1,
>      'audio0' => 1,
> +    'rng0' => 1,
>  };
>  
>  my $generaloptions = {
> @@ -801,6 +803,36 @@ my sub check_vm_create_hostpci_perm {
>      return 1;
>  };
>  
> +my sub check_rng_perm {
> +    my ($rpcenv, $authuser, $vmid, $pool, $opt, $value) = @_;
> +
> +    return 1 if $authuser eq 'root@pam';
> +
> +    $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.HWType']);
> +
> +    my $device = PVE::JSONSchema::parse_property_string('pve-qm-rng', $value);
> +    if ($device->{source}) {
> +	if ($device->{source} eq '/dev/hwrng') {
> +	    die "only root can set '$opt' config for a non-mapped Hardware RNG device\n";
> +	}
> +    }
> +
> +    return 1;
> +}
> +
> +my sub check_vm_create_rng_perm {
> +    my ($rpcenv, $authuser, $vmid, $pool, $param) = @_;
> +
> +    return 1 if $authuser eq 'root@pam';
> +
> +    foreach my $opt (keys %{$param}) {
> +	next if $opt !~ m/^rng\d+$/;
> +	check_rng_perm($rpcenv, $authuser, $vmid, $pool, $opt, $param->{$opt});
> +    }
> +
> +    return 1;
> +};

there only ever is one rng device at the moment, so this could be
dropped..

> +
>  my $check_vm_modify_config_perm = sub {
>      my ($rpcenv, $authuser, $vmid, $pool, $key_list) = @_;
>  
> @@ -1114,6 +1146,7 @@ __PACKAGE__->register_method({
>  	    &$check_vm_create_serial_perm($rpcenv, $authuser, $vmid, $pool, $param);
>  	    check_vm_create_usb_perm($rpcenv, $authuser, $vmid, $pool, $param);
>  	    check_vm_create_hostpci_perm($rpcenv, $authuser, $vmid, $pool, $param);
> +	    check_vm_create_rng_perm($rpcenv, $authuser, $vmid, $pool, $param);

and this could instead be

check_rng_perm($rpcenv, $authuser, $vmid, $pool, 'rng0', $param->{rng0})
    if $param->{rng0};

?

>  
>  	    PVE::QemuServer::check_bridge_access($rpcenv, $authuser, $param);
>  	    &$check_cpu_model_access($rpcenv, $authuser, $param);
> @@ -2005,6 +2038,10 @@ my $update_vm_api  = sub {
>  		    check_hostpci_perm($rpcenv, $authuser, $vmid, undef, $opt, $val);
>  		    PVE::QemuConfig->add_to_pending_delete($conf, $opt, $force);
>  		    PVE::QemuConfig->write_config($vmid, $conf);
> +		} elsif ($opt eq m/^rng\d+$/) {
> +		    check_rng_perm($rpcenv, $authuser, $vmid, undef, $opt, $val);
> +		    PVE::QemuConfig->add_to_pending_delete($conf, $opt, $force);
> +		    PVE::QemuConfig->write_config($vmid, $conf);
>  		} elsif ($opt eq 'tags') {
>  		    assert_tag_permissions($vmid, $val, '', $rpcenv, $authuser);
>  		    delete $conf->{$opt};
> @@ -2095,6 +2132,12 @@ my $update_vm_api  = sub {
>  		    }
>  		    check_hostpci_perm($rpcenv, $authuser, $vmid, undef, $opt, $param->{$opt});
>  		    $conf->{pending}->{$opt} = $param->{$opt};
> +		} elsif ($opt =~ m/^rng\d+$/) {
> +		    if (my $oldvalue = $conf->{$opt}) {
> +			check_rng_perm($rpcenv, $authuser, $vmid, undef, $opt, $oldvalue);
> +		    }
> +		    check_rng_perm($rpcenv, $authuser, $vmid, undef, $opt, $param->{$opt});
> +		    $conf->{pending}->{$opt} = $param->{$opt};
>  		} elsif ($opt eq 'tags') {
>  		    assert_tag_permissions($vmid, $conf->{$opt}, $param->{$opt}, $rpcenv, $authuser);
>  		    $conf->{pending}->{$opt} = PVE::GuestHelpers::get_unique_tags($param->{$opt});
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 70518924..cc69eeb1 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -6398,8 +6398,17 @@ sub check_mapping_access {
>  	    } else {
>  		die "either 'host' or 'mapping' must be set.\n";
>  	    }
> -       }
> -   }
> +	} elsif ($opt =~ m/^rng\d+$/) {
> +	    my $device = PVE::JSONSchema::parse_property_string('pve-qm-rng', $conf->{$opt});
> +
> +	    if ($device->{source}) {
> +		if ($device->{source} eq '/dev/hwrng') {
> +		    die "only root can set '$opt' config for a non-mapped Hardware RNG device\n"
> +			if $user ne 'root@pam';
> +		}
> +	    }
> +	}

those are three nested ifs that could be a single one?

if ($device->{source} && $device->{source} eq '/dev/hwrng' && $user ne 'root@pam') {

}

I guess we could even move the root check for the whole sub up front as
a precursor patch, to simplify the if conditions a bit..

I also wonder whether it makes sense to allow /dev/urandom and
/dev/random as mappings if they are not restricted in the first place
when used directly? what's the advantage of that?

> +    }
>  };
>  
>  sub check_restore_permissions {
> -- 
> 2.39.5
> 
> 
> 
> _______________________________________________
> pve-devel mailing list
> pve-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
> 
> 
> 


_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [pve-devel] [PATCH qemu-server v3 11/11] let VirtIO RNG devices source entropy from mapped HWRNGs
  2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 11/11] let VirtIO RNG devices source entropy from mapped HWRNGs Filip Schauer
@ 2025-02-11 12:34   ` Fabian Grünbichler
  0 siblings, 0 replies; 16+ messages in thread
From: Fabian Grünbichler @ 2025-02-11 12:34 UTC (permalink / raw)
  To: Proxmox VE development discussion

On February 10, 2025 4:37 pm, Filip Schauer wrote:
> This allows a user with the Mapping.Modify privilege on /mapping/hwrng
> to configure a hardware RNG mapping. A less privileged user with the
> Mapping.Use privilege can then pass the mapped hardware RNG device as an
> entropy source to a VirtIO RNG device.
> 
> Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
> ---
>  PVE/API2/Qemu.pm      |  5 +++++
>  PVE/QemuServer.pm     |  5 +++++
>  PVE/QemuServer/RNG.pm | 25 +++++++++++++++++++++++++
>  3 files changed, 35 insertions(+)
> 
> diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
> index 194e6357..33b3625b 100644
> --- a/PVE/API2/Qemu.pm
> +++ b/PVE/API2/Qemu.pm
> @@ -812,9 +812,14 @@ my sub check_rng_perm {
>  
>      my $device = PVE::JSONSchema::parse_property_string('pve-qm-rng', $value);
>      if ($device->{source}) {
> +	# Backward compatibility for non-mapped /dev/hwrng
>  	if ($device->{source} eq '/dev/hwrng') {
>  	    die "only root can set '$opt' config for a non-mapped Hardware RNG device\n";
>  	}
> +    } elsif ($device->{mapping}) {
> +	$rpcenv->check_full($authuser, "/mapping/hwrng/$device->{mapping}", ['Mapping.Use']);
> +    } else {
> +	die "either 'source' or 'mapping' must be set.\n";
>      }
>  
>      return 1;
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index cc69eeb1..82a6c65d 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -6402,10 +6402,15 @@ sub check_mapping_access {
>  	    my $device = PVE::JSONSchema::parse_property_string('pve-qm-rng', $conf->{$opt});
>  
>  	    if ($device->{source}) {
> +		# Backward compatibility for non-mapped /dev/hwrng
>  		if ($device->{source} eq '/dev/hwrng') {
>  		    die "only root can set '$opt' config for a non-mapped Hardware RNG device\n"
>  			if $user ne 'root@pam';
>  		}
> +	    } elsif ($device->{mapping}) {
> +		$rpcenv->check_full($user, "/mapping/hwrng/$device->{mapping}", ['Mapping.Use']);
> +	    } else {
> +		die "either 'source' or 'mapping' must be set.\n";

this is handled here, but if both are set then the parser will silently
drop them (see below).. seems a bit inconsistent, for other mappings the
parser enforces this already as well..

>  	    }
>  	}
>      }
> diff --git a/PVE/QemuServer/RNG.pm b/PVE/QemuServer/RNG.pm
> index ae5b2530..3ee19852 100644
> --- a/PVE/QemuServer/RNG.pm
> +++ b/PVE/QemuServer/RNG.pm
> @@ -4,6 +4,7 @@ use strict;
>  use warnings;
>  
>  use PVE::JSONSchema;
> +use PVE::Mapping::HWRNG;
>  use PVE::Tools qw(file_read_firstline);
>  
>  use PVE::QemuServer::PCI qw(print_pci_addr);
> @@ -22,11 +23,20 @@ my $rng_fmt = {
>  	type => 'string',
>  	enum => ['/dev/urandom', '/dev/random', '/dev/hwrng'],
>  	default_key => 1,
> +	optional => 1,
>  	description => "The file on the host to gather entropy from. Using urandom does *not*"
>  	    ." decrease security in any meaningful way, as it's still seeded from real entropy, and"
>  	    ." the bytes provided will most likely be mixed with real entropy on the guest as well."
>  	    ." '/dev/hwrng' can be used to pass through a hardware RNG from the host.",
>      },
> +    mapping => {
> +	optional => 1,
> +	type => 'string',
> +	format_description => 'mapping-id',
> +	format => 'pve-configid',
> +	description => "The ID of a cluster wide mapping. When specified, entropy is gathered from"
> +	    ." a hardware RNG on the host. Either this or the default-key 'source' must be set.",
> +    },
>      max_bytes => {
>  	type => 'integer',
>  	description => "Maximum bytes of entropy allowed to get injected into the guest every"
> @@ -65,6 +75,11 @@ sub parse_rng {
>      my $res = eval { PVE::JSONSchema::parse_property_string($rng_fmt, $value) };
>      warn $@ if $@;
>  
> +    my $source = $res->{source};
> +    my $mapping = $res->{mapping};
> +
> +    return if $source && $mapping; # not a valid configuration
> +
>      return $res;
>  }
>  
> @@ -89,9 +104,19 @@ sub get_rng_source_path {
>      my ($rng) = @_;
>  
>      my $source = $rng->{source};
> +    my $mapping = $rng->{mapping};
> +
> +    return if $source && $mapping; # not a valid configuration

this cannot really happen, since the parser already dropped this
combination?

>  
>      if (defined($source)) {
>  	return $source;
> +    } elsif (defined($mapping)) {
> +	my $devices = PVE::Mapping::HWRNG::find_on_current_node($mapping);
> +	die "Hardware RNG mapping not found for '$mapping'\n" if !$devices || !scalar($devices->@*);
> +	die "More than one Hardware RNG mapping per host not supported\n"
> +	    if scalar($devices->@*) > 1;
> +
> +	return $devices->[0]->{path};

should we maybe simplify this - and just defined a single static mapping
for now for /dev/hwrng, so that we have an ACL path to refer to?

>      }
>  
>      return;
> -- 
> 2.39.5
> 
> 
> 
> _______________________________________________
> pve-devel mailing list
> pve-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
> 
> 
> 


_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user
  2025-02-10 15:37 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Filip Schauer
                   ` (10 preceding siblings ...)
  2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 11/11] let VirtIO RNG devices source entropy from mapped HWRNGs Filip Schauer
@ 2025-02-11 12:34 ` Fabian Grünbichler
  2025-02-18 11:17   ` Filip Schauer
  11 siblings, 1 reply; 16+ messages in thread
From: Fabian Grünbichler @ 2025-02-11 12:34 UTC (permalink / raw)
  To: Proxmox VE development discussion

On February 10, 2025 4:37 pm, Filip Schauer wrote:
> Allow users with the VM.Config.HWType privilege to configure VirtIO RNG
> devices on VMs with either /dev/urandom or /dev/random as the entropy
> source.
> 
> Further introduce hardware RNG device mapping to be able to selectively
> allow non-root users with the Mapping.Use privilege to configure
> hardware RNG devices as entropy sources.

some high level questions here:

- this series allows direct access to /dev/urandom and /dev/random, but
  also allows setting up mappings to them (the mapping seems unnecessary)
- the only other (restricted) value is /dev/hwrng

wouldn't it be easier to just define an ACL path for /dev/hwrng, and
skip all the mapping setup if the only sensible mapping you can set up
is a single one for /dev/hwrng?

do we expect other hardware RNG device paths in the future?

else the only benefit of the full-fledged mapping is that you can
"alias" and describe RNG sources and limit them to certain nodes, and I
am not sure that is worth all this machinery and an extra config file ;)
aliasing makes very little sense if there is only three valid choices
that have descriptive names anyway. I also expect that most people using
this would want to give the VM access to the hwrng on all nodes..

other than this the series looks good to me, just a few nits (see
individual patches)

> 
> Changes since v2:
> * Restrict RNG device format to enum of
> * Add descriptive commit message
> * Code style fixes
> * Remove outdated remarks about entropy stravation of /dev/random
> * Split helpers for VirtIO RNG command line arguments into its own
>   commit
> * Add explicit "use PVE::QemuServer::RNG;" statement to PVE/API2/Qemu.pm
> * Fix "map: type check ('array') failed" error when adding a mapping in
>   the UI
> * ui: split resource mapping types into tabbed views
> 
> Changes since v1:
> * Restrict use of /dev/hwrng to the root user
> * introduce hardware RNG mapping
> 
> pve-guest-common:
> 
> Filip Schauer (1):
>   mapping: add a hardware RNG mapping config
> 
>  src/Makefile             |   1 +
>  src/PVE/Mapping/HWRNG.pm | 147 +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 148 insertions(+)
>  create mode 100644 src/PVE/Mapping/HWRNG.pm
> 
> 
> pve-cluster:
> 
> Filip Schauer (1):
>   cfs: add 'mapping/hwrng.cfg' to observed files
> 
>  src/PVE/Cluster.pm  | 1 +
>  src/pmxcfs/status.c | 1 +
>  2 files changed, 2 insertions(+)
> 
> 
> pve-manager:
> 
> Filip Schauer (5):
>   introduce hardware rng mapping api
>   introduce hardware rng scanning api
>   ui: add hardware RNG resource mapping
>   ui: allow use of mapped hardware RNGs as entropy sources for VMs
>   ui: split resource mapping types into tabbed views
> 
>  PVE/API2/Cluster/Mapping.pm                   |   7 +
>  PVE/API2/Cluster/Mapping/HWRNG.pm             | 286 ++++++++++++++++++
>  PVE/API2/Cluster/Mapping/Makefile             |   5 +-
>  PVE/API2/Hardware.pm                          |   7 +
>  PVE/API2/Hardware/HWRNG.pm                    |  47 +++
>  PVE/API2/Hardware/Makefile                    |   1 +
>  www/manager6/Makefile                         |  12 +-
>  www/manager6/data/PermPathStore.js            |   1 +
>  www/manager6/dc/Config.js                     |  41 +--
>  www/manager6/form/HWRNGMapSelector.js         |  99 ++++++
>  www/manager6/qemu/HardwareView.js             |   9 +-
>  www/manager6/qemu/RNGEdit.js                  |  79 +++--
>  www/manager6/resource-map/HWRNGMapEdit.js     | 149 +++++++++
>  www/manager6/resource-map/HWRNGMapView.js     |  76 +++++
>  .../{window => resource-map}/PCIMapEdit.js    |   2 +-
>  .../{dc => resource-map}/PCIMapView.js        |   4 +-
>  www/manager6/resource-map/ResourceMapView.js  |  23 ++
>  .../{window => resource-map}/USBMapEdit.js    |   2 +-
>  .../{dc => resource-map}/USBMapView.js        |   4 +-
>  19 files changed, 778 insertions(+), 76 deletions(-)
>  create mode 100644 PVE/API2/Cluster/Mapping/HWRNG.pm
>  create mode 100644 PVE/API2/Hardware/HWRNG.pm
>  create mode 100644 www/manager6/form/HWRNGMapSelector.js
>  create mode 100644 www/manager6/resource-map/HWRNGMapEdit.js
>  create mode 100644 www/manager6/resource-map/HWRNGMapView.js
>  rename www/manager6/{window => resource-map}/PCIMapEdit.js (99%)
>  rename www/manager6/{dc => resource-map}/PCIMapView.js (96%)
>  create mode 100644 www/manager6/resource-map/ResourceMapView.js
>  rename www/manager6/{window => resource-map}/USBMapEdit.js (99%)
>  rename www/manager6/{dc => resource-map}/USBMapView.js (95%)
> 
> 
> qemu-server:
> 
> Filip Schauer (4):
>   refactor: move rng related code into its own module
>   add helpers for VirtIO RNG command line arguments
>   allow non-root users to set /dev/u?random as an RNG source
>   let VirtIO RNG devices source entropy from mapped HWRNGs
> 
>  PVE/API2/Qemu.pm        |  48 +++++++++++++
>  PVE/QemuServer.pm       |  97 ++++++-------------------
>  PVE/QemuServer/Makefile |   1 +
>  PVE/QemuServer/RNG.pm   | 153 ++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 224 insertions(+), 75 deletions(-)
>  create mode 100644 PVE/QemuServer/RNG.pm
> 
> 
> Summary over all repositories:
>   27 files changed, 1152 insertions(+), 151 deletions(-)
> 
> -- 
> Generated by git-murpp 0.6.0
> 
> 
> _______________________________________________
> pve-devel mailing list
> pve-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
> 
> 
> 


_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user
  2025-02-11 12:34 ` [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Fabian Grünbichler
@ 2025-02-18 11:17   ` Filip Schauer
  0 siblings, 0 replies; 16+ messages in thread
From: Filip Schauer @ 2025-02-18 11:17 UTC (permalink / raw)
  To: Proxmox VE development discussion, Fabian Grünbichler

Superseded by:
https://lore.proxmox.com/pve-devel/20250218111102.40055-1-f.schauer@proxmox.com/

On 11/02/2025 13:34, Fabian Grünbichler wrote:
> do we expect other hardware RNG device paths in the future?

No, not in the near future at least.
There is a patch [1] for this from 2016, but this was never realized.

On 11/02/2025 13:34, Fabian Grünbichler wrote:
> wouldn't it be easier to just define an ACL path for /dev/hwrng, and
> skip all the mapping setup if the only sensible mapping you can set up
> is a single one for /dev/hwrng?

Removed the resource mapping additions and instead introduced the
/mapping/hwrng ACL path in v4.

[1] 
https://lore.kernel.org/all/1469477255-26824-1-git-send-email-keithp@keithp.com/T



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2025-02-18 11:18 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-02-10 15:37 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Filip Schauer
2025-02-10 15:37 ` [pve-devel] [PATCH guest-common v3 01/11] mapping: add a hardware RNG mapping config Filip Schauer
2025-02-10 15:37 ` [pve-devel] [PATCH cluster v3 02/11] cfs: add 'mapping/hwrng.cfg' to observed files Filip Schauer
2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 03/11] introduce hardware rng mapping api Filip Schauer
2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 04/11] introduce hardware rng scanning api Filip Schauer
2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 05/11] ui: add hardware RNG resource mapping Filip Schauer
2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 06/11] ui: allow use of mapped hardware RNGs as entropy sources for VMs Filip Schauer
2025-02-10 15:37 ` [pve-devel] [PATCH manager v3 07/11] ui: split resource mapping types into tabbed views Filip Schauer
2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 08/11] refactor: move rng related code into its own module Filip Schauer
2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 09/11] add helpers for VirtIO RNG command line arguments Filip Schauer
2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 10/11] allow non-root users to set /dev/u?random as an RNG source Filip Schauer
2025-02-11 12:34   ` Fabian Grünbichler
2025-02-10 15:37 ` [pve-devel] [PATCH qemu-server v3 11/11] let VirtIO RNG devices source entropy from mapped HWRNGs Filip Schauer
2025-02-11 12:34   ` Fabian Grünbichler
2025-02-11 12:34 ` [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v3 00/11] fix #5657: allow configuring RNG device as non-root user Fabian Grünbichler
2025-02-18 11:17   ` Filip Schauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal