Bug 1001773

Summary: [RFE] virt-manager: Add ability to pull system entropy from host
Product: Red Hat Enterprise Linux 7 Reporter: Amit Shah <amit.shah>
Component: virt-managerAssignee: Giuseppe Scrivano <gscrivan>
Status: CLOSED CURRENTRELEASE QA Contact: Virtualization Bugs <virt-bugs>
Severity: medium Docs Contact:
Priority: high    
Version: 7.0CC: acathrow, akong, amit.shah, areis, bcao, bsarathy, crobinso, dallan, dayleparker, dyuan, juzhang, kseifried, lagarcia, laine, lcui, lnovich, mazhang, mhomolov, michen, mkenneth, mkletzan, mzhan, pkrempa, qzhang, sgrubb, shu, sradvan, tburke, trichard, tzheng, virt-maint
Target Milestone: rcKeywords: FutureFeature
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: virt-manager-0.10.0-5.el7 Doc Type: Enhancement
Doc Text:
Story Points: ---
Clone Of: 1001770 Environment:
Last Closed: 2014-06-13 11:00:37 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 786407, 1001770    
Bug Blocks: 896690, 786408, 883503, 969788, 973003, 973416, 973871, 989636, 989641    
Attachments:
Description Flags
udp by wireshark none

Comment 6 hyao@redhat.com 2013-10-15 13:04:48 UTC
# rpm -qa libvirt virt-manager
libvirt-1.1.1-8.el7.x86_64
virt-manager-0.10.0-4.el7.noarch


For virt-manager GUI testing on virtio-rng, I tested the following scenario :

1. Add a rng device as type:random device:/dev/random.  there's a /dev/hwrng device in the rhel 6.4 guest, and I could get the random number from the following python. 
python
import os
f = os.open('/dev/hwrng', os.O_RDONLY)
os.read(f, 10)
'\x01\xa5\x8a\xad\x9a\xc6\x8f\xc2\xe1\x9b'

2. Add a rng device as type:random device:/dev/random, rate(period):2000, rate(byte):1024.  there's a /dev/hwrng device in the rhel 6.4 guest, and I could get the random number from the following python too. 
# python 
Python 2.6.6 (r266:84292, Oct 12 2012, 14:23:48) 
[GCC 4.4.6 20120305 (Red Hat 4.4.6-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> f = os.open('/dev/hwrng',os.O_RDONLY)
>>> os.read(f,10)
'P\xcf\x7f\x95=\xb2\xd3\xe9#\xe5'


3. 
a, Add the rng device as type:Entropy Gathering Daemon, Host:localhost, Service: 1024, Backendtype: TCP,Mode: connect, rate(period):2000, rate(byte):1024.
b. #cat /dev/urandom | nc -l localhost 1024
c. Start the guest. 
d. # ps aux | grep qemu
...-chardev socket,id=charrng0,host=localhost,port=1024 -object rng-egd,chardev=charrng0,id=rng0 -device virtio-rng-pci,rng=rng0,max-bytes=1024,period=2000,bus=pci.0,addr=0x6

e. there's a /dev/hwrng device. I could get the random number
# dd if=/dev/hwrng of=/tmp/hello
^C90+1 records in
90+0 records out
46080 bytes (46 kB) copied, 89.8489 s, 0.5 kB/s

4. 
a. Add the rng device as type:Entropy Gathering Daemon, Host:localhost, Service: 1024, Backendtype: TCP,Mode: Bind
b. #cat /dev/urandom | nc -l localhost 1024
c. Start the guest. 
d. # ps aux | grep qemu
...--chardev socket,id=charrng0,host=localhost,port=1024,server,nowait -object rng-egd,chardev=charrng0,id=rng0 -device virtio-rng-pci,rng=rng0,bus=pci.0,addr=0x6
 there's a /dev/hwrng device. but i could not get random number from
 # dd if=/dev/hwrng of=/tmp/hello
 or 
 # cat /dev/hwrng

Seems this scenario failed. 
5.
a, Add the rng device as type:Entropy Gathering Daemon, Host:localhost, Service: 1024, Backendtype: UDP,Mode: connect, 
b.  Start the guest. 
c. # ps aux | grep qemu
... -chardev udp,id=charrng0,host=localhost,port=1025,localaddr=,localport=0 -object rng-egd,chardev=charrng0,id=rng0 -device virtio-rng-pci,rng=rng0,bus=pci.0,addr=0x6
 there's a /dev/hwrng device. I could get the random number
# dd if=/dev/hwrng of=/tmp/hello 
or 
# cat /dev/hwrng


6. 
a, Add the rng device as type:Entropy Gathering Daemon, Host:localhost, Service: 1024, Backendtype: UDP,Mode: bind,
Get the following error message:  
Error adding device: internal error: Missing source service attribute for char device


For virt-install, 
1. # virt-install -n demo -r 1024 -f /var/lib/libvirt/images/rhel6.4.img --import --rng /dev/random
# ps aux | grep qemu
....-object rng-random,id=rng0,filename=/dev/random -device virtio-rng-pci,rng=rng0,bus=pci.0,addr=0x6

Could get random number in the guest.

2.#virt-install -n demo -r 1024 -f /var/lib/libvirt/images/rhel6.4.img --import --rng egd,backend_host=localhost,backend_service=8000,backend_type=tcp
 # ps aux | grep qemu
...-chardev socket,id=charrng0,host=localhost,port=8000 -object rng-egd,chardev=charrng0,id=rng0 -device virtio-rng-pci,rng=rng0,bus=pci.0,addr=0x6

Could get random number in the guest.

Comment 7 Giuseppe Scrivano 2013-10-15 18:37:24 UTC
the error at point "6" is generated by libvirt.

I am not sure whether mode="bind" is supposed to work with UDP or not, but in both cases I would prefer to not check for it in virt-manager and let libvirt generates the error, if any.

If libvirt doesn't support mode="bind" with UDP, then probably the error string should be improved.

(I've set NEEDINFO to Peter, please change it if not correct)

Comment 8 Amos Kong 2013-10-16 05:27:57 UTC
UDP socket chardev is just a data channel. If qemu set a connect UDP socket(client), you should create a listen UDP socket(server), and write the random data to remote socket when client connects the server.

If qemu set a listen UDP socket, you should create a connect UDP socket, and try to connect the server socket, and write data to remote socket.

It's same with TCP socket, or unix socket.

----

For point 5:

you can server the UDP server first
# cat /dev/random | nc -U -l 1025

then launch qemu guest.

Comment 9 Martin Kletzander 2013-10-16 07:31:48 UTC
I'd say TCP mode bind is supported, but you used "nc -l" to feed it, but mode bind means qemu is listening as well, so you need to connect there.  That means running the guest and then sending is something (to "nc localhost 1024").  Could you re-check that?

Other than that the UDP option sould be changed.  In case UDP is selected, both bind and connect sources need to be defined to know where to send requests and where to get the responses from.

Comment 10 hyao@redhat.com 2013-10-16 08:21:50 UTC
(In reply to Martin Kletzander from comment #9)
> I'd say TCP mode bind is supported, but you used "nc -l" to feed it, but
> mode bind means qemu is listening as well, so you need to connect there. 
> That means running the guest and then sending is something (to "nc localhost
> 1024").  Could you re-check that?
> 
> Other than that the UDP option sould be changed.  In case UDP is selected,
> both bind and connect sources need to be defined to know where to send
> requests and where to get the responses from.

the TCP mode bind, I run the guest and then use # cat /dev/urandom | nc localhost 1024. 
I can get the random number in the guest by 
# cat /dev/hwrng

Comment 11 Giuseppe Scrivano 2013-10-17 10:14:02 UTC
this is the XML I get on my machine, trough virt-manager, when I try to set up an EGD device over UDP:

--- Original XML
+++ New XML
@@ -75,5 +75,10 @@
     <memballoon model="virtio">
       <address type="pci" domain="0x0000" bus="0x00" slot="0x07" function="0x0"/>
     </memballoon>
+    <rng model="virtio">
+      <backend model="egd" type="udp">
+        <source mode="bind" host="localhost" service="708"/>
+      </backend>
+    </rng>
   </devices>
 </domain>

and I get the same error (as described at point 6):

internal error: Missing source service attribute for char device

Can you confirm this behaviour?  If this is the case, the problem seems to be in libvirt.

I have also tried manually in virsh dropping the additional "host" attribute, and I get the same error.

Comment 12 Martin Kletzander 2013-10-18 13:48:26 UTC
(In reply to Giuseppe Scrivano from comment #11)
The thing is, that EGD works both ways (one way request, second way response) and with UDP you need to know where to send the request and where to wait for the response, so you need both source mode='bind' and mode='connect' elements.  The only problem is that if you don't supply bind, but supply connect (with UDP), there will be no error produced. The reason behind this is that qemu is happy when it has somewhere to send the request and doesn't care if there is no way for incoming data to get in.  That's why we should remove the "bind/connect" option when UDP is selected in that dialog and force user to fill in both addresses (one for listening to data and one for sending requests). This is not needed for TCP, of course.

Comment 15 hyao@redhat.com 2013-11-01 10:45:08 UTC
Test with the latest packages below:

# rpm -qa libvirt qemu-kvm virt-manager
virt-manager-0.10.0-5.el7.noarch
libvirt-1.1.1-10.el7.x86_64
qemu-kvm-1.5.3-11.el7.x86_64

1.Add udp backend rng device as below: 

# virsh dumpxml T | grep rng -A 5
    <rng model='virtio'>
      <backend model='egd' type='udp'>
        <source mode='bind' host='localhost' service='1024'/>
        <source mode='connect' host='localhost' service='1708'/>
      </backend>
    </rng>
  </devices>
</domain>

Feed the VM rng device by python script 
# python
Python 2.7.4 (default, May  6 2013, 07:26:49) 
[GCC 4.8.0 20130419 (Red Hat 4.8.0-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> UDP_IP = "127.0.0.1"
>>> UDP_PORT = 1708
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> sock.bind((UDP_IP, UDP_PORT))
>>> while True:
...  data, addr = sock.recvfrom(1024)
...  print "SEND DATA"
...  sock.sendto ("AB" * 1024, addr)

Start the VM, and try to get random data by
#dd if=/dev/hwrng of=/tmp/udp_test

Can't get the random data.

2. I can get random data for random type rng device and TCP backend device(both bind and connect). 

Based on the above mentioned steps, I assign the bug.

Comment 16 Giuseppe Scrivano 2013-11-01 11:28:26 UTC
can you please post the command line arguments to qemu?  Could you also run a packet sniffer, such as wireshark, to debug your local UDP traffic and check if qemu is requesting any data (I've found useful to set this filter in wireshark to avoid noise: "udp.dstport==1708 or udp.srcport==1708")?

This is the configuration I am using here:

libvirt XML configuration (obtained trough virt-manager):
    <rng model='virtio'>
      <backend model='egd' type='udp'>
        <source mode='bind' host='127.0.0.1' service='1710'/>
        <source mode='connect' host='127.0.0.1' service='1708'/>
      </backend>
    </rng>


arguments to qemu I get:

"-chardev udp,id=charrng0,host=127.0.0.1,port=1708,localaddr=127.0.0.1,localport=1710 -object rng-egd,chardev=charrng0,id=rng0 -device virtio-rng-pci,rng=rng0,bus=pci.0,addr=0x8"


I am using this python script to feed data to the rng virtio device:

####################################################################
import socket

UDP_IP = "127.0.0.1"
UDP_PORT = 1708

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))

while True:
    data, addr = sock.recvfrom(1024)
    print "SEND DATA"
    sock.sendto ("AB" * 1024, addr)
####################################################################

and on the guest machine, that is running Fedora 19 (kernel: 3.11.6-200.fc19.i686 #1 SMP Fri Oct 18 23:00:01 UTC 2013 i686 i686 i386 GNU/Linux), I can do:

[root@localhost giuseppe]# head -c2 /dev/hwrng; echo
AB
[root@localhost giuseppe]# head -c2 /dev/hwrng; echo
AB


Noteworthy, I am using the development version of qemu: v1.4.0-4479-gec426ff

Comment 17 hyao@redhat.com 2013-11-06 05:16:50 UTC
Created attachment 820191 [details]
udp by wireshark

Hi, Giuseppe Scrivano

# rpm -qa libvirt virt-manager qemu-kvm kernel 
virt-manager-0.10.0-5.el7.noarch
qemu-kvm-1.5.3-10.el7.x86_64
libvirt-1.1.1-11.el7.x86_64


# virsh dumpxml r65 | grep rng -A 10
    <rng model='virtio'>
      <backend model='egd' type='udp'>
        <source mode='bind' host='127.0.0.1' service='1710'/>
        <source mode='connect' host='127.0.0.1' service='1708'/>
      </backend>
    </rng>


the arguments sent to qemu:
..-chardev udp,id=charrng0,host=127.0.0.1,port=1708,localaddr=127.0.0.1,localport=1710 -object rng-egd,chardev=charrng0,id=rng0 -device virtio-rng-pci,rng=rng0,bus=pci.0,addr=0x8

Use the script to feed rng device
####################################################################
import socket

UDP_IP = "127.0.0.1"
UDP_PORT = 1708

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))

while True:
    data, addr = sock.recvfrom(1024)
    print "SEND DATA"
    sock.sendto ("AB" * 1024, addr)
####################################################################

I export the package dissection as plain txt and attach it in the bug. 

Also I use tcpdump to dump the traffic on port 1708
# tcpdump -n -vv "dst host 127.0.0.1 and (dst port 1708 or src port 1708)"
tcpdump: WARNING: macvtap0: no IPv4 address assigned
tcpdump: listening on macvtap0, link-type EN10MB (Ethernet), capture size 65535 bytes
^C
0 packets captured
0 packets received by filter
0 packets dropped by kernel
3 packets dropped by interface

In the guest, no random data is generated: 
[root@localhost ~]# head -c2 /dev/hwrng; echo
^C

Comment 18 Giuseppe Scrivano 2013-11-07 09:09:37 UTC
I was able to get it to work on RHEL-7.  I have used a Fedora 19 live CD as guest OS.

# rpm -qa libvirt virt-manager qemu-kvm kernel 
kernel-3.10.0-29.el7.x86_64
virt-manager-0.10.0-5.el7.noarch
qemu-kvm-1.5.3-13.el7.x86_64
kernel-3.10.0-33.el7.x86_64

this is the complete "virsh dumpxml test" output for the virtual machine I have used:

<domain type='qemu' id='5'>
  <name>test</name>
  <uuid>3bc753b7-1580-4b52-98d7-1fe60d3114ee</uuid>
  <memory unit='KiB'>1536000</memory>
  <currentMemory unit='KiB'>1536000</currentMemory>
  <vcpu placement='static'>1</vcpu>
  <resource>
    <partition>/machine</partition>
  </resource>
  <os>
    <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type>
    <boot dev='cdrom'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <clock offset='utc'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='cdrom'>
      <driver name='qemu' type='raw'/>
      <source file='/home/giuseppe/Fedora-19.iso'/>
      <target dev='hdc' bus='ide'/>
      <readonly/>
      <alias name='ide0-1-0'/>
      <address type='drive' controller='0' bus='1' target='0' unit='0'/>
    </disk>
    <controller type='usb' index='0'>
      <alias name='usb0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pci-root'>
      <alias name='pci.0'/>
    </controller>
    <controller type='ide' index='0'>
      <alias name='ide0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
    </controller>
    <controller type='virtio-serial' index='0'>
      <alias name='virtio-serial0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </controller>
    <interface type='network'>
      <mac address='52:54:00:4d:ff:22'/>
      <source network='default'/>
      <target dev='vnet0'/>
      <model type='virtio'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <serial type='pty'>
      <source path='/dev/pts/1'/>
      <target port='0'/>
      <alias name='serial0'/>
    </serial>
    <console type='pty' tty='/dev/pts/1'>
      <source path='/dev/pts/1'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>
    </console>
    <channel type='spicevmc'>
      <target type='virtio' name='com.redhat.spice.0'/>
      <alias name='channel0'/>
      <address type='virtio-serial' controller='0' bus='0' port='1'/>
    </channel>
    <input type='mouse' bus='ps2'/>
    <graphics type='spice' port='5900' autoport='yes' listen='127.0.0.1'>
      <listen type='address' address='127.0.0.1'/>
    </graphics>
    <sound model='ich6'>
      <alias name='sound0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </sound>
    <video>
      <model type='qxl' ram='65536' vram='65536' heads='1'/>
      <alias name='video0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    <memballoon model='virtio'>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
    </memballoon>
    <rng model='virtio'>
      <backend model='egd' type='udp'>
        <source mode='bind' host='127.0.0.1' service='1710'/>
        <source mode='connect' host='127.0.0.1' service='1708'/>
      </backend>
    </rng>
  </devices>
  <seclabel type='dynamic' model='selinux' relabel='yes'>
    <label>system_u:system_r:svirt_tcg_t:s0:c243,c472</label>
    <imagelabel>system_u:object_r:svirt_image_t:s0:c243,c472</imagelabel>
  </seclabel>
</domain>

Can you please share the network configuration you have used for the VM?

Comment 19 hyao@redhat.com 2013-11-07 12:23:14 UTC
# rpm -qa libvirt virt-manager qemu-kvm kernel
kernel-3.10.0-33.el7.x86_64
qemu-kvm-1.5.3-10.el7.x86_64
libvirt-1.1.1-11.el7.x86_64
virt-manager-0.10.0-5.el7.noarch

Set up a fedora and rhel guest on the host installed by latest tree:
Add the rng device like below:
with Type: Entropy Gathering Daemon, Backend type: UDP, Host: 127.0.0.1 port 1708, Bind Host: 127.0.0.1 port 1710.  

# virsh dumpxml rhel | grep rng -A 10
    <rng model='virtio'>
      <backend model='egd' type='udp'>
        <source mode='bind' host='127.0.0.1' service='1710'/>
        <source mode='connect' host='127.0.0.1' service='1708'/>
      </backend>
    </rng>

Use the script to feed rng device
####################################################################
import socket

UDP_IP = "127.0.0.1"
UDP_PORT = 1708

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))

while True:
    data, addr = sock.recvfrom(1024)
    print "SEND DATA"
    sock.sendto ("AB" * 1024, addr)
####################################################################

Check the access to the server by netcat
# echo hello | nc -u 127.0.0.1 1708
ABABABABABABABABABABABABABABABABABABABAB...


Start the guest rhel/fedora, and check if the random data are generated by /dev/hwrng:
#head -c 2 /dev/hwrng
AB

Based on the previous comment 16 and the steps, I verified this bug.

Comment 20 Ludek Smid 2014-06-13 11:00:37 UTC
This request was resolved in Red Hat Enterprise Linux 7.0.

Contact your manager or support representative in case you have further questions about the request.