* [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user
@ 2025-01-29 15:53 Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH guest-common v2 1/9] mapping: add a hardware RNG mapping config Filip Schauer
` (9 more replies)
0 siblings, 10 replies; 15+ messages in thread
From: Filip Schauer @ 2025-01-29 15:53 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 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 (4):
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
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 | 3 +
www/manager6/data/PermPathStore.js | 1 +
www/manager6/dc/Config.js | 10 +
www/manager6/dc/HWRNGMapView.js | 76 +++++++
www/manager6/form/HWRNGMapSelector.js | 99 +++++++++
www/manager6/qemu/HardwareView.js | 9 +-
www/manager6/qemu/RNGEdit.js | 79 ++++---
www/manager6/window/HWRNGMapEdit.js | 149 ++++++++++++++
14 files changed, 748 insertions(+), 31 deletions(-)
create mode 100644 PVE/API2/Cluster/Mapping/HWRNG.pm
create mode 100644 PVE/API2/Hardware/HWRNG.pm
create mode 100644 www/manager6/dc/HWRNGMapView.js
create mode 100644 www/manager6/form/HWRNGMapSelector.js
create mode 100644 www/manager6/window/HWRNGMapEdit.js
qemu-server:
Filip Schauer (3):
refactor: move rng related code into its own module
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 | 47 ++++++++++++
PVE/QemuServer.pm | 101 +++++++-------------------
PVE/QemuServer/Makefile | 1 +
PVE/QemuServer/RNG.pm | 156 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 229 insertions(+), 76 deletions(-)
create mode 100644 PVE/QemuServer/RNG.pm
Summary over all repositories:
22 files changed, 1127 insertions(+), 107 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] 15+ messages in thread
* [pve-devel] [PATCH guest-common v2 1/9] mapping: add a hardware RNG mapping config
2025-01-29 15:53 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Filip Schauer
@ 2025-01-29 15:53 ` Filip Schauer
2025-01-30 12:18 ` Fiona Ebner
2025-01-29 15:53 ` [pve-devel] [PATCH cluster v2 2/9] cfs: add 'mapping/hwrng.cfg' to observed files Filip Schauer
` (8 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Filip Schauer @ 2025-01-29 15:53 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..fb9fa8c
--- /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',
+ pattern => qr/^\/dev\/.+$/,
+ },
+ 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] 15+ messages in thread
* [pve-devel] [PATCH cluster v2 2/9] cfs: add 'mapping/hwrng.cfg' to observed files
2025-01-29 15:53 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH guest-common v2 1/9] mapping: add a hardware RNG mapping config Filip Schauer
@ 2025-01-29 15:53 ` Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH manager v2 3/9] introduce hardware rng mapping api Filip Schauer
` (7 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Filip Schauer @ 2025-01-29 15:53 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] 15+ messages in thread
* [pve-devel] [PATCH manager v2 3/9] introduce hardware rng mapping api
2025-01-29 15:53 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH guest-common v2 1/9] mapping: add a hardware RNG mapping config Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH cluster v2 2/9] cfs: add 'mapping/hwrng.cfg' to observed files Filip Schauer
@ 2025-01-29 15:53 ` Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH manager v2 4/9] introduce hardware rng scanning api Filip Schauer
` (6 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Filip Schauer @ 2025-01-29 15:53 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] 15+ messages in thread
* [pve-devel] [PATCH manager v2 4/9] introduce hardware rng scanning api
2025-01-29 15:53 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Filip Schauer
` (2 preceding siblings ...)
2025-01-29 15:53 ` [pve-devel] [PATCH manager v2 3/9] introduce hardware rng mapping api Filip Schauer
@ 2025-01-29 15:53 ` Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH manager v2 5/9] ui: add hardware RNG resource mapping Filip Schauer
` (5 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Filip Schauer @ 2025-01-29 15:53 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] 15+ messages in thread
* [pve-devel] [PATCH manager v2 5/9] ui: add hardware RNG resource mapping
2025-01-29 15:53 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Filip Schauer
` (3 preceding siblings ...)
2025-01-29 15:53 ` [pve-devel] [PATCH manager v2 4/9] introduce hardware rng scanning api Filip Schauer
@ 2025-01-29 15:53 ` Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH manager v2 6/9] ui: allow use of mapped hardware RNGs as entropy sources for VMs Filip Schauer
` (4 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Filip Schauer @ 2025-01-29 15:53 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..15e9008a
--- /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 (values.id) {
+ 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] 15+ messages in thread
* [pve-devel] [PATCH manager v2 6/9] ui: allow use of mapped hardware RNGs as entropy sources for VMs
2025-01-29 15:53 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Filip Schauer
` (4 preceding siblings ...)
2025-01-29 15:53 ` [pve-devel] [PATCH manager v2 5/9] ui: add hardware RNG resource mapping Filip Schauer
@ 2025-01-29 15:53 ` Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH qemu-server v2 7/9] refactor: move rng related code into its own module Filip Schauer
` (3 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Filip Schauer @ 2025-01-29 15:53 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] 15+ messages in thread
* [pve-devel] [PATCH qemu-server v2 7/9] refactor: move rng related code into its own module
2025-01-29 15:53 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Filip Schauer
` (5 preceding siblings ...)
2025-01-29 15:53 ` [pve-devel] [PATCH manager v2 6/9] ui: allow use of mapped hardware RNGs as entropy sources for VMs Filip Schauer
@ 2025-01-29 15:53 ` Filip Schauer
2025-01-30 12:17 ` Fiona Ebner
2025-01-29 15:53 ` [pve-devel] [PATCH qemu-server v2 8/9] allow non-root users to set /dev/u?random as an RNG source Filip Schauer
` (2 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Filip Schauer @ 2025-01-29 15:53 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
PVE/QemuServer.pm | 83 +++---------------------
PVE/QemuServer/Makefile | 1 +
PVE/QemuServer/RNG.pm | 135 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 145 insertions(+), 74 deletions(-)
create mode 100644 PVE/QemuServer/RNG.pm
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 5cde94a1..93e65825 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -61,6 +61,7 @@ use PVE::QemuServer::Memory qw(get_current_memory);
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;
use PVE::QemuServer::USB;
my $have_sdn;
@@ -249,39 +250,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 $meta_info_fmt = {
'ctime' => {
type => 'integer',
@@ -724,7 +692,7 @@ EODESCR
},
rng0 => {
type => 'string',
- format => $rng_fmt,
+ format => $PVE::QemuServer::RNG::rng_fmt,
description => "Configure a VirtIO-based Random Number Generator.",
optional => 1,
},
@@ -2078,16 +2046,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 parse_meta_info {
my ($value) = @_;
@@ -3940,20 +3898,14 @@ sub config_to_command {
}
}
- my $rng = $conf->{rng0} ? parse_rng($conf->{rng0}) : undef;
+ my $rng = $conf->{rng0} ? PVE::QemuServer::RNG::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 = PVE::QemuServer::RNG::print_rng_object('rng0', $rng);
+ my $rng_device = PVE::QemuServer::RNG::print_rng_device(
+ 'rng0', $rng, $bridges, $arch, $machine_type
+ );
+ push @$devices, '-object', $rng_object;
+ push @$devices, '-device', $rng_device;
}
my $spice_port;
@@ -4235,23 +4187,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 89d12091..72c287fc 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..f7a62f3b
--- /dev/null
+++ b/PVE/QemuServer/RNG.pm
@@ -0,0 +1,135 @@
+package PVE::QemuServer::RNG;
+
+use strict;
+use warnings;
+
+use PVE::QemuServer::PCI qw(print_pci_addr);
+use PVE::JSONSchema;
+use PVE::Tools qw(file_read_firstline);
+use base 'Exporter';
+
+our @EXPORT_OK = qw(
+parse_rng
+check_rng_source
+print_rng_device
+print_rng_object
+);
+
+our $rng_fmt = {
+ source => {
+ type => 'string',
+ enum => ['/dev/urandom', '/dev/random', '/dev/hwrng'],
+ default_key => 1,
+ optional => 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,
+ },
+};
+
+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 $@;
+
+ my $source = $res->{source};
+
+ 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";
+ }
+}
+
+sub get_rng_source_path {
+ my ($rng) = @_;
+
+ my $source = $rng->{source};
+
+ if (defined($source)) {
+ return $source;
+ }
+
+ return;
+}
+
+sub print_rng_device {
+ my ($id, $rng, $bridges, $arch, $machine) = @_;
+
+ return if !$rng;
+
+ my $source_path = get_rng_source_path($rng);
+ check_rng_source($source_path);
+
+ 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 {
+ my ($id, $rng) = @_;
+
+ return 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] 15+ messages in thread
* [pve-devel] [PATCH qemu-server v2 8/9] allow non-root users to set /dev/u?random as an RNG source
2025-01-29 15:53 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Filip Schauer
` (6 preceding siblings ...)
2025-01-29 15:53 ` [pve-devel] [PATCH qemu-server v2 7/9] refactor: move rng related code into its own module Filip Schauer
@ 2025-01-29 15:53 ` Filip Schauer
2025-01-30 12:18 ` Fiona Ebner
2025-01-29 15:53 ` [pve-devel] [PATCH qemu-server v2 9/9] let VirtIO RNG devices source entropy from mapped HWRNGs Filip Schauer
2025-01-30 12:17 ` [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Fiona Ebner
9 siblings, 1 reply; 15+ messages in thread
From: Filip Schauer @ 2025-01-29 15:53 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 | 42 ++++++++++++++++++++++++++++++++++++++++++
PVE/QemuServer.pm | 13 +++++++++++--
2 files changed, 53 insertions(+), 2 deletions(-)
diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index db356b7e..8262c9d4 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -670,6 +670,7 @@ my $hwtypeoptions = {
'vga' => 1,
'watchdog' => 1,
'audio0' => 1,
+ 'rng0' => 1,
};
my $generaloptions = {
@@ -798,6 +799,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) = @_;
@@ -1111,6 +1142,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);
@@ -2008,6 +2040,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};
@@ -2098,6 +2134,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 93e65825..606f51fa 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -6602,8 +6602,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] 15+ messages in thread
* [pve-devel] [PATCH qemu-server v2 9/9] let VirtIO RNG devices source entropy from mapped HWRNGs
2025-01-29 15:53 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Filip Schauer
` (7 preceding siblings ...)
2025-01-29 15:53 ` [pve-devel] [PATCH qemu-server v2 8/9] allow non-root users to set /dev/u?random as an RNG source Filip Schauer
@ 2025-01-29 15:53 ` Filip Schauer
2025-01-30 12:17 ` [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Fiona Ebner
9 siblings, 0 replies; 15+ messages in thread
From: Filip Schauer @ 2025-01-29 15:53 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, 33 insertions(+), 2 deletions(-)
diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 8262c9d4..e8567ff3 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -808,9 +808,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 606f51fa..4a36e778 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -6606,10 +6606,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 f7a62f3b..ede5ffde 100644
--- a/PVE/QemuServer/RNG.pm
+++ b/PVE/QemuServer/RNG.pm
@@ -5,6 +5,7 @@ use warnings;
use PVE::QemuServer::PCI qw(print_pci_addr);
use PVE::JSONSchema;
+use PVE::Mapping::HWRNG;
use PVE::Tools qw(file_read_firstline);
use base 'Exporter';
@@ -25,8 +26,15 @@ our $rng_fmt = {
." 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.",
+ ." with real entropy on the guest as well.",
+ },
+ 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',
@@ -68,6 +76,9 @@ sub parse_rng {
warn $@ if $@;
my $source = $res->{source};
+ my $mapping = $res->{mapping};
+
+ return if $source && $mapping; # not a valid configuration
return $res;
}
@@ -93,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] 15+ messages in thread
* Re: [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user
2025-01-29 15:53 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Filip Schauer
` (8 preceding siblings ...)
2025-01-29 15:53 ` [pve-devel] [PATCH qemu-server v2 9/9] let VirtIO RNG devices source entropy from mapped HWRNGs Filip Schauer
@ 2025-01-30 12:17 ` Fiona Ebner
2025-02-10 15:47 ` Filip Schauer
9 siblings, 1 reply; 15+ messages in thread
From: Fiona Ebner @ 2025-01-30 12:17 UTC (permalink / raw)
To: Proxmox VE development discussion, Filip Schauer
Am 29.01.25 um 16:53 schrieb Filip Schauer:
> 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.
>
It's a lot of overhead for a very specific kind of device. What irks me
is that we have a lot of boilerplate duplication for each new mapping
type, also for the API endpoints. Nothing specific to your series of
course, but maybe something we could/should address? In the UI, it
probably would also be better to have a separate view for each mapping
type? Markus needs directory mappings for virtio-fs and then we would
have 4 different mapping kinds in a single view, which IMHO is just too
much.
Maybe we can introduce a dedicated base module for Mapping Section
configs? And also have standard options for the common params in the
schema. Same applies for the API endpoints, would be nice to have a way
to more easily generate them or at least capture the functionality that
is 1:1 with some helpers. Again, nothing specific to your series. Just
putting it out there for discussion or if somebody wants to grab that
task :)
When I try to add a mapping in the UI, I get
Parameter verification failed. (400)
map: type check ('array') failed
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [pve-devel] [PATCH qemu-server v2 7/9] refactor: move rng related code into its own module
2025-01-29 15:53 ` [pve-devel] [PATCH qemu-server v2 7/9] refactor: move rng related code into its own module Filip Schauer
@ 2025-01-30 12:17 ` Fiona Ebner
0 siblings, 0 replies; 15+ messages in thread
From: Fiona Ebner @ 2025-01-30 12:17 UTC (permalink / raw)
To: Proxmox VE development discussion, Filip Schauer
Am 29.01.25 um 16:53 schrieb Filip Schauer:
> Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
> ---
> PVE/QemuServer.pm | 83 +++---------------------
> PVE/QemuServer/Makefile | 1 +
> PVE/QemuServer/RNG.pm | 135 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 145 insertions(+), 74 deletions(-)
> create mode 100644 PVE/QemuServer/RNG.pm
>
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 5cde94a1..93e65825 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -61,6 +61,7 @@ use PVE::QemuServer::Memory qw(get_current_memory);
> 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;
> use PVE::QemuServer::USB;
>
> my $have_sdn;
> @@ -249,39 +250,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 $meta_info_fmt = {
> 'ctime' => {
> type => 'integer',
Does not apply, because this got moved recently ;)
> @@ -724,7 +692,7 @@ EODESCR
> },
> rng0 => {
> type => 'string',
> - format => $rng_fmt,
> + format => $PVE::QemuServer::RNG::rng_fmt,
> description => "Configure a VirtIO-based Random Number Generator.",
> optional => 1,
> },
Could instead use the standard option you define in the RNG module.
> @@ -2078,16 +2046,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 parse_meta_info {
> my ($value) = @_;
>
Does not apply, because this got moved recently ;)
> @@ -3940,20 +3898,14 @@ sub config_to_command {
> }
> }
>
> - my $rng = $conf->{rng0} ? parse_rng($conf->{rng0}) : undef;
> + my $rng = $conf->{rng0} ? PVE::QemuServer::RNG::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 = PVE::QemuServer::RNG::print_rng_object('rng0', $rng);
> + my $rng_device = PVE::QemuServer::RNG::print_rng_device(
> + 'rng0', $rng, $bridges, $arch, $machine_type
> + );
Style nit: that's not how multiline function calls are usually wrapped
in our Perl code base:
https://pve.proxmox.com/wiki/Perl_Style_Guide#Wrapping_Arguments
> + push @$devices, '-object', $rng_object;
> + push @$devices, '-device', $rng_device;
> }
>
> my $spice_port;
Would be nice to have the moving to a dedicated module be separate from
adding the new helpers.
> @@ -4235,23 +4187,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 89d12091..72c287fc 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..f7a62f3b
> --- /dev/null
> +++ b/PVE/QemuServer/RNG.pm
> @@ -0,0 +1,135 @@
> +package PVE::QemuServer::RNG;
> +
> +use strict;
> +use warnings;
> +
> +use PVE::QemuServer::PCI qw(print_pci_addr);
> +use PVE::JSONSchema;
> +use PVE::Tools qw(file_read_firstline);
> +use base 'Exporter';
Style nit: The QemuServer::PCI module should be grouped below and I'd
prefer having a blank before it:
https://lore.proxmox.com/pve-devel/e24881cf-bfd2-4063-bde2-99f41031f0f0@proxmox.com/
Having the 'use base' be last is fine, but I'd also prefer a blank
before it.
> +
> +our @EXPORT_OK = qw(
> +parse_rng
> +check_rng_source
> +print_rng_device
> +print_rng_object
> +);
> +
> +our $rng_fmt = {
> + source => {
> + type => 'string',
> + enum => ['/dev/urandom', '/dev/random', '/dev/hwrng'],
> + default_key => 1,
> + optional => 1,
Adding the optional should not be part of this patch.
> + 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.",
The part about /dev/random is outdated as you pointed out in v1 ;)
> + },
> + 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!).",
The part about /dev/random is outdated as you pointed out in v1 ;)
> + 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);
Since you register the format here, you don't need to make $rng_fmt
shared with 'our' or? (Still need to include the module in QemuServer.pm
to have registering come first).
> +
> +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 $@;
> +
> + my $source = $res->{source};
Unused variable, should be part of a later patch.
> +
> + 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";
> + }
> +}
> +
> +sub get_rng_source_path {
> + my ($rng) = @_;
> +
> + my $source = $rng->{source};
> +
> + if (defined($source)) {
> + return $source;
> + }
> +
> + return;
> +}
> +
> +sub print_rng_device {
I'd add _commandline to reduce potential for confusion
> + my ($id, $rng, $bridges, $arch, $machine) = @_;
> +
> + return if !$rng;
Isn't failing better? IMHO caller should first check that it has
something to print rather than check the result.
> +
> + my $source_path = get_rng_source_path($rng);
> + check_rng_source($source_path);
Since the source is not part of the result, maybe not check it here, but
only in print_rng_object()?
> +
> + 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 {
I'd add _commandline to reduce potential for confusion
> + my ($id, $rng) = @_;
> +
> + return if !$rng;
Isn't failing better? IMHO caller should first check that it has
something to print rather than check the result.
> +
> + my $source_path = get_rng_source_path($rng);
> + check_rng_source($source_path);
> +
> + return "rng-random,filename=$source_path,id=$id";
> +}
> +
> +1;
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [pve-devel] [PATCH qemu-server v2 8/9] allow non-root users to set /dev/u?random as an RNG source
2025-01-29 15:53 ` [pve-devel] [PATCH qemu-server v2 8/9] allow non-root users to set /dev/u?random as an RNG source Filip Schauer
@ 2025-01-30 12:18 ` Fiona Ebner
0 siblings, 0 replies; 15+ messages in thread
From: Fiona Ebner @ 2025-01-30 12:18 UTC (permalink / raw)
To: Proxmox VE development discussion, Filip Schauer
Am 29.01.25 um 16:53 schrieb Filip Schauer:
> 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 | 42 ++++++++++++++++++++++++++++++++++++++++++
> PVE/QemuServer.pm | 13 +++++++++++--
> 2 files changed, 53 insertions(+), 2 deletions(-)
>
> diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
> index db356b7e..8262c9d4 100644
> --- a/PVE/API2/Qemu.pm
> +++ b/PVE/API2/Qemu.pm
> @@ -670,6 +670,7 @@ my $hwtypeoptions = {
> 'vga' => 1,
> 'watchdog' => 1,
> 'audio0' => 1,
> + 'rng0' => 1,
> };
>
> my $generaloptions = {
> @@ -798,6 +799,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);
Nit: missing explicit use statement for the RNG module (that is where
the format is registered).
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [pve-devel] [PATCH guest-common v2 1/9] mapping: add a hardware RNG mapping config
2025-01-29 15:53 ` [pve-devel] [PATCH guest-common v2 1/9] mapping: add a hardware RNG mapping config Filip Schauer
@ 2025-01-30 12:18 ` Fiona Ebner
0 siblings, 0 replies; 15+ messages in thread
From: Fiona Ebner @ 2025-01-30 12:18 UTC (permalink / raw)
To: Proxmox VE development discussion, Filip Schauer
Am 29.01.25 um 16:53 schrieb Filip Schauer:
> +my $map_fmt = {
> + node => get_standard_option('pve-node'),
> + path => {
> + description => "The path to the device node of the entropy source.",
> + type => 'string',
> + pattern => qr/^\/dev\/.+$/,
Style nit: could use | or ! as the regex delimiter to improve readability
Can we restrict this up-front somehow? I'd even be inclined to start out
with the enum we had in qemu-server. A generic path below /dev seems
prone to abuse at a first glance. Mapping.Modify for hardware RNG should
not ease access to other devices. And the check_rng_source() doesn't
currently offer any real protection either (just restricts the
/dev/hwrng case).
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user
2025-01-30 12:17 ` [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Fiona Ebner
@ 2025-02-10 15:47 ` Filip Schauer
0 siblings, 0 replies; 15+ messages in thread
From: Filip Schauer @ 2025-02-10 15:47 UTC (permalink / raw)
To: Fiona Ebner, Proxmox VE development discussion
Superseded by:
https://lore.proxmox.com/pve-devel/20250210153734.103381-1-f.schauer@proxmox.com/
On 30/01/2025 13:17, Fiona Ebner wrote:
> It's a lot of overhead for a very specific kind of device. What irks me
> is that we have a lot of boilerplate duplication for each new mapping
> type, also for the API endpoints. Nothing specific to your series of
> course, but maybe something we could/should address?
Agree
On 30/01/2025 13:17, Fiona Ebner wrote:
> In the UI, it
> probably would also be better to have a separate view for each mapping
> type?
I split resource mapping types into tabbed views in v3.
On 30/01/2025 13:17, Fiona Ebner wrote:
> When I try to add a mapping in the UI, I get
> Parameter verification failed. (400)
> map: type check ('array') failed
Fixed in v3
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2025-02-10 15:47 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-01-29 15:53 [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH guest-common v2 1/9] mapping: add a hardware RNG mapping config Filip Schauer
2025-01-30 12:18 ` Fiona Ebner
2025-01-29 15:53 ` [pve-devel] [PATCH cluster v2 2/9] cfs: add 'mapping/hwrng.cfg' to observed files Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH manager v2 3/9] introduce hardware rng mapping api Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH manager v2 4/9] introduce hardware rng scanning api Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH manager v2 5/9] ui: add hardware RNG resource mapping Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH manager v2 6/9] ui: allow use of mapped hardware RNGs as entropy sources for VMs Filip Schauer
2025-01-29 15:53 ` [pve-devel] [PATCH qemu-server v2 7/9] refactor: move rng related code into its own module Filip Schauer
2025-01-30 12:17 ` Fiona Ebner
2025-01-29 15:53 ` [pve-devel] [PATCH qemu-server v2 8/9] allow non-root users to set /dev/u?random as an RNG source Filip Schauer
2025-01-30 12:18 ` Fiona Ebner
2025-01-29 15:53 ` [pve-devel] [PATCH qemu-server v2 9/9] let VirtIO RNG devices source entropy from mapped HWRNGs Filip Schauer
2025-01-30 12:17 ` [pve-devel] [PATCH cluster/guest-common/manager/qemu-server v2 0/9] fix #5657: allow configuring RNG device as non-root user Fiona Ebner
2025-02-10 15:47 ` Filip Schauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox