From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:50084) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SUeDO-0006UT-Fx for qemu-devel@nongnu.org; Wed, 16 May 2012 09:24:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SUeDL-0000dU-KH for qemu-devel@nongnu.org; Wed, 16 May 2012 09:24:29 -0400 Received: from mail-pb0-f45.google.com ([209.85.160.45]:41182) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SUeDL-0000dC-AL for qemu-devel@nongnu.org; Wed, 16 May 2012 09:24:27 -0400 Received: by pbbro12 with SMTP id ro12so1429089pbb.4 for ; Wed, 16 May 2012 06:24:25 -0700 (PDT) Message-ID: <4FB3AA86.3080507@codemonkey.ws> Date: Wed, 16 May 2012 08:24:22 -0500 From: Anthony Liguori MIME-Version: 1.0 References: In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH 1/1] virtio-rng: device to send host entropy to guest List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Amit Shah Cc: qemu list On 05/16/2012 06:30 AM, Amit Shah wrote: > The Linux kernel already has a virtio-rng driver, this is the device > implementation. > > When Linux needs more entropy, it puts a buffer in the vq. We then put > entropy into that buffer, and push it back to the guest. > > Feeding randomness from host's /dev/urandom into the guest is > sufficient, so this is a simple implementation that opens /dev/urandom > and reads from it whenever required. > > Invocation is simple: > > qemu ... -device virtio-rng-pci > > In the guest, we see > > $ cat /sys/devices/virtual/misc/hw_random/rng_available > virtio > > $ cat /sys/devices/virtual/misc/hw_random/rng_current > virtio > > There are ways to extend the device to be more generic and collect > entropy from other sources, but this is simple enough and works for now. > > Signed-off-by: Amit Shah It's not this simple unfortunately. If you did this with libvirt, one guest could exhaust the available entropy for the remaining guests. This could be used as a mechanism for one guest to attack another (reducing the available entropy for key generation). You need to rate limit the amount of entropy that a guest can obtain to allow management tools to mitigate this attack. Regards, Anthony Liguori > --- > Makefile.objs | 1 + > hw/pci.h | 1 + > hw/virtio-pci.c | 50 +++++++++++++++++++++ > hw/virtio-rng.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > hw/virtio-rng.h | 18 ++++++++ > hw/virtio.h | 2 + > 6 files changed, 202 insertions(+), 0 deletions(-) > create mode 100644 hw/virtio-rng.c > create mode 100644 hw/virtio-rng.h > > diff --git a/Makefile.objs b/Makefile.objs > index 70c5c79..5850762 100644 > --- a/Makefile.objs > +++ b/Makefile.objs > @@ -210,6 +210,7 @@ user-obj-y += $(qom-obj-twice-y) > hw-obj-y = > hw-obj-y += vl.o loader.o > hw-obj-$(CONFIG_VIRTIO) += virtio-console.o > +hw-obj-$(CONFIG_VIRTIO) += virtio-rng.o > hw-obj-y += usb/libhw.o > hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o > hw-obj-y += fw_cfg.o > diff --git a/hw/pci.h b/hw/pci.h > index 8d0aa49..0a22f91 100644 > --- a/hw/pci.h > +++ b/hw/pci.h > @@ -76,6 +76,7 @@ > #define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 > #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 > #define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 > +#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 > > #define FMT_PCIBUS PRIx64 > > diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c > index 4a4413d..7f2d630 100644 > --- a/hw/virtio-pci.c > +++ b/hw/virtio-pci.c > @@ -812,6 +812,28 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev) > return virtio_exit_pci(pci_dev); > } > > +static int virtio_rng_init_pci(PCIDevice *pci_dev) > +{ > + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); > + VirtIODevice *vdev; > + > + vdev = virtio_rng_init(&pci_dev->qdev); > + if (!vdev) { > + return -1; > + } > + virtio_init_pci(proxy, vdev); > + return 0; > +} > + > +static int virtio_rng_exit_pci(PCIDevice *pci_dev) > +{ > + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); > + > + virtio_pci_stop_ioeventfd(proxy); > + virtio_rng_exit(proxy->vdev); > + return virtio_exit_pci(pci_dev); > +} > + > static Property virtio_blk_properties[] = { > DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), > DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block), > @@ -937,6 +959,33 @@ static TypeInfo virtio_balloon_info = { > .class_init = virtio_balloon_class_init, > }; > > +static Property virtio_rng_properties[] = { > + DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > +static void virtio_rng_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); > + > + k->init = virtio_rng_init_pci; > + k->exit = virtio_rng_exit_pci; > + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; > + k->device_id = PCI_DEVICE_ID_VIRTIO_RNG; > + k->revision = VIRTIO_PCI_ABI_VERSION; > + k->class_id = PCI_CLASS_OTHERS; > + dc->reset = virtio_pci_reset; > + dc->props = virtio_rng_properties; > +} > + > +static TypeInfo virtio_rng_info = { > + .name = "virtio-rng-pci", > + .parent = TYPE_PCI_DEVICE, > + .instance_size = sizeof(VirtIOPCIProxy), > + .class_init = virtio_rng_class_init, > +}; > + > static int virtio_scsi_init_pci(PCIDevice *pci_dev) > { > VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); > @@ -998,6 +1047,7 @@ static void virtio_pci_register_types(void) > type_register_static(&virtio_serial_info); > type_register_static(&virtio_balloon_info); > type_register_static(&virtio_scsi_info); > + type_register_static(&virtio_rng_info); > } > > type_init(virtio_pci_register_types) > diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c > new file mode 100644 > index 0000000..e1f3d1c > --- /dev/null > +++ b/hw/virtio-rng.c > @@ -0,0 +1,130 @@ > +/* A virtio device for feeding entropy into a guest. > + * > + * Copyright 2012 Red Hat, Inc. > + * Copyright 2012 Amit Shah > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or > + * (at your option) any later version. See the COPYING file in the > + * top-level directory. > + */ > + > +#include "iov.h" > +#include "qdev.h" > +#include "virtio.h" > +#include "virtio-rng.h" > + > +typedef struct VirtIORNG { > + VirtIODevice vdev; > + > + DeviceState *qdev; > + > + /* Only one vq - guest puts a buffer on it when it needs entropy */ > + VirtQueue *vq; > + > + int input_fd; > +} VirtIORNG; > + > +static void handle_input(VirtIODevice *vdev, VirtQueue *vq) > +{ > + VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev); > + VirtQueueElement elem; > + char *buf; > + ssize_t size, offset, ret; > + > + if (!virtqueue_pop(vq,&elem)) { > + return; > + } > + size = iov_size(elem.in_sg, elem.in_num); > + > + buf = g_malloc(size); > + do { > + ret = read(vrng->input_fd, buf, size); > + } while (ret == -1&& errno == EINTR); > + if (ret< 0) { > + /* We can't get randomness -- give up for now. */ > + virtqueue_push(vq,&elem, 0); > + goto skip; > + } > + > + offset = 0; > + size = ret; > + while (offset< size) { > + size_t len; > + > + /* We've already popped the first elem */ > + if (offset&& !virtqueue_pop(vq,&elem)) { > + break; > + } > + > + len = iov_from_buf(elem.in_sg, elem.in_num, > + buf + offset, 0, size - offset); > + offset += len; > + > + virtqueue_push(vq,&elem, len); > + } > +skip: > + g_free(buf); > + virtio_notify(vdev, vq); > +} > + > +static uint32_t get_features(VirtIODevice *vdev, uint32_t f) > +{ > + return f; > +} > + > +static void virtio_rng_save(QEMUFile *f, void *opaque) > +{ > + VirtIORNG *vrng = opaque; > + > + virtio_save(&vrng->vdev, f); > +} > + > +static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id) > +{ > + VirtIORNG *vrng = opaque; > + > + if (version_id != 1) { > + return -EINVAL; > + } > + virtio_load(&vrng->vdev, f); > + > + return 0; > +} > + > +VirtIODevice *virtio_rng_init(DeviceState *dev) > +{ > + VirtIORNG *vrng; > + VirtIODevice *vdev; > + int input_fd; > + > + input_fd = open("/dev/urandom", O_RDONLY); > + if (input_fd< 0) { > + error_report("error %d opening /dev/urandom", errno); > + return NULL; > + } > + > + vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0, > + sizeof(VirtIORNG)); > + > + vrng = DO_UPCAST(VirtIORNG, vdev, vdev); > + > + vrng->input_fd = input_fd; > + > + vrng->vq = virtio_add_queue(vdev, 8, handle_input); > + vrng->vdev.get_features = get_features; > + > + vrng->qdev = dev; > + register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save, > + virtio_rng_load, vrng); > + > + return vdev; > +} > + > +void virtio_rng_exit(VirtIODevice *vdev) > +{ > + VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev); > + > + close(vrng->input_fd); > + unregister_savevm(vrng->qdev, "virtio-rng", vrng); > + virtio_cleanup(vdev); > +} > diff --git a/hw/virtio-rng.h b/hw/virtio-rng.h > new file mode 100644 > index 0000000..2e1eba3 > --- /dev/null > +++ b/hw/virtio-rng.h > @@ -0,0 +1,18 @@ > +/* > + * Virtio RNG Support > + * > + * Copyright Red Hat, Inc. 2012 > + * Copyright Amit Shah > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or > + * (at your option) any later version. See the COPYING file in the > + * top-level directory. > + */ > + > +#ifndef _QEMU_VIRTIO_RNG_H > +#define _QEMU_VIRTIO_RNG_H > + > +/* The Virtio ID for the virtio rng device */ > +#define VIRTIO_ID_RNG 4 > + > +#endif > diff --git a/hw/virtio.h b/hw/virtio.h > index 0aef7d1..0315e0c 100644 > --- a/hw/virtio.h > +++ b/hw/virtio.h > @@ -201,6 +201,7 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial); > VirtIODevice *virtio_balloon_init(DeviceState *dev); > typedef struct VirtIOSCSIConf VirtIOSCSIConf; > VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf); > +VirtIODevice *virtio_rng_init(DeviceState *dev); > #ifdef CONFIG_LINUX > VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf); > #endif > @@ -211,6 +212,7 @@ void virtio_blk_exit(VirtIODevice *vdev); > void virtio_serial_exit(VirtIODevice *vdev); > void virtio_balloon_exit(VirtIODevice *vdev); > void virtio_scsi_exit(VirtIODevice *vdev); > +void virtio_rng_exit(VirtIODevice *vdev); > > #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \ > DEFINE_PROP_BIT("indirect_desc", _state, _field, \