Am 2/20/20 um 6:10 PM schrieb Stefan Reiter: > Allow a user to add a virtio-rng-pci (an emulated hardware random > number generator) to a VM with the rng0 setting. The setting is > version_guard()-ed. > > Limit the selection of entropy source to one of three: > /dev/urandom (preferred): Non-blocking kernel entropy source > /dev/random: Blocking kernel source > /dev/hwrng: Hardware RNG on the host for passthrough > > QEMU itself defaults to /dev/urandom (or the equivalent getrandom() > call) if no source file is given, but I don't fully trust that > behaviour to stay constant, considering the documentation [0] already > disagrees with the code [1], so let's always specify the file ourselves. > > /dev/urandom is preferred, since it prevents host entropy starvation. > The quality of randomness is still good enough to emulate a hwrng, since > a) it's still seeded from the kernel's true entropy pool periodically > and b) it's mixed with true entropy in the guest as well. > > Additionally, all sources about entropy predicition attacks I could find > mention that to predict /dev/urandom results, /dev/random has to be > accessed or manipulated in one way or the other - this is not possible > from a VM however, as the entropy we're talking about comes from the > *hosts* blocking pool. > > More about the entropy and security implications of the non-blocking > interface in [2] and [3]. > > Note further that only one /dev/hwrng exists at any given time, if > multiple RNGs are available, only the one selected in > '/sys/devices/virtual/misc/hw_random/rng_current' will feed the file. > Selecting this is left as an exercise to the user, if at all required. > > We limit the available entropy to 1 KiB/s by default, but allow the user > to override this. Interesting to note is that the limiter does not work > linearly, i.e. max_bytes=1024/period=1000 means that up to 1 KiB of data > becomes available on a 1000 millisecond timer, not that 1 KiB is > streamed to the guest over the course of one second - hence the > configurable period. > > The default used here is the same as given in the QEMU documentation [0] > and has been verified to affect entropy availability in a guest by > measuring /dev/random throughput. 1 KiB/s is enough to avoid any > early-boot entropy shortages, and already has a significant impact on > /dev/random availability in the guest. > > [0] https://wiki.qemu.org/Features/VirtIORNG > [1] > https://git.qemu.org/?p=qemu.git;a=blob;f=crypto/random-platform.c;h=f92f96987d7d262047c7604b169a7fdf11236107;hb=HEAD > [2] https://lwn.net/Articles/261804/ > [3] https://lwn.net/Articles/808575/ > > Signed-off-by: Stefan Reiter <s.rei...@proxmox.com> > --- > > Includes a version bump currently set to 4.1+pve2. Would need to be changed if > applied later.
Why?? This is a new option a user has explicit to set, either it's there or not. I'd bump the version just for every new option... > > Tested with all three options (luckily enough, my system has a hwrng called > 'ccp-1-rng', which seems to come from the AMD CPU's Cryptographic > Coprocessor). > > /dev/random does indeed lead to entropy starvation, while /dev/urandom does > not. > rngtest (from rng-tools) reports high-quality randomness inside VMs, no matter > what source is selected. > > PVE/QemuServer.pm | 73 +++++++++++++++++++++++++++++++++++++++++++ > PVE/QemuServer/PCI.pm | 1 + > 2 files changed, 74 insertions(+) > > diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm > index 23176dd..0065a3c 100644 > --- a/PVE/QemuServer.pm > +++ b/PVE/QemuServer.pm > @@ -219,6 +219,43 @@ 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 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, > @@ -607,6 +644,12 @@ EODESCR > description => 'Tags of the VM. This is only meta information.', > optional => 1, > }, > + rng0 => { > + type => 'string', > + format => $rng_fmt, > + description => "Configure a VirtIO-based Random Number Generator.", > + optional => 1, > + }, > }; > > my $cicustom_fmt = { > @@ -2348,6 +2391,16 @@ sub parse_vga { > return $res; > } > > +sub parse_rng { > + my ($value) = @_; > + > + return undef if !$value; > + > + my $res = eval { PVE::JSONSchema::parse_property_string($rng_fmt, > $value) }; > + warn $@ if $@; > + return $res; > +} > + > PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device); > sub verify_usb_device { > my ($value, $noerr) = @_; > @@ -3827,6 +3880,26 @@ sub config_to_command { > } > } > > + my $rng = parse_rng($conf->{rng0}) if $conf->{rng0}; > + if ($rng && &$version_guard(4, 1, 2)) { > + 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"; > + } > + > + # mostly relevant for /dev/hwrng, but doesn't hurt to check others too > + die "cannot create VirtIO RNG device: source file '$rng->{source}' > doesn't exist\n" > + if ! -e $rng->{source}; > + > + 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 $spice_port; > > if ($qxlnum) { > diff --git a/PVE/QemuServer/PCI.pm b/PVE/QemuServer/PCI.pm > index c3b4716..4d9ce26 100644 > --- a/PVE/QemuServer/PCI.pm > +++ b/PVE/QemuServer/PCI.pm > @@ -72,6 +72,7 @@ sub get_pci_addr_map { > 'net31' => { bus => 1, addr => 26 }, > 'xhci' => { bus => 1, addr => 27 }, > 'pci.4' => { bus => 1, addr => 28 }, > + 'rng0' => { bus => 1, addr => 29 }, > 'virtio6' => { bus => 2, addr => 1 }, > 'virtio7' => { bus => 2, addr => 2 }, > 'virtio8' => { bus => 2, addr => 3 }, > _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel