All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anthony Liguori <anthony@codemonkey.ws>
To: Amit Shah <amit.shah@redhat.com>
Cc: qemu list <qemu-devel@nongnu.org>
Subject: Re: [Qemu-devel] [PATCH 1/1] virtio-rng: device to send host entropy to guest
Date: Wed, 16 May 2012 08:24:22 -0500	[thread overview]
Message-ID: <4FB3AA86.3080507@codemonkey.ws> (raw)
In-Reply-To: <aa4c6913ca2bc37e049f04f498c6414a4ec544bd.1337167727.git.amit.shah@redhat.com>

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<amit.shah@redhat.com>

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<amit.shah@redhat.com>
> + *
> + * 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<amit.shah@redhat.com>
> + *
> + * 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, \

  parent reply	other threads:[~2012-05-16 13:24 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-05-16 11:30 [Qemu-devel] [PATCH 1/1] virtio-rng: device to send host entropy to guest Amit Shah
2012-05-16 11:38 ` Paolo Bonzini
2012-05-16 11:54   ` Amit Shah
2012-05-16 13:24 ` Anthony Liguori [this message]
2012-05-16 13:45   ` Daniel P. Berrange
2012-05-16 13:48     ` Anthony Liguori
2012-05-16 13:53       ` Daniel P. Berrange
2012-05-16 14:02         ` Anthony Liguori
2012-05-16 17:28           ` Amit Shah
2012-05-21 19:32       ` Amit Shah
2012-05-16 17:26     ` Amit Shah
2012-05-16 18:24       ` Anthony Liguori
2012-05-21 19:37         ` Amit Shah
2012-05-16 17:21   ` Amit Shah
2012-05-16 18:23     ` Anthony Liguori
2012-05-21 19:39       ` Amit Shah
2012-05-21 20:34         ` Anthony Liguori
2012-05-22 12:57           ` Amit Shah

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4FB3AA86.3080507@codemonkey.ws \
    --to=anthony@codemonkey.ws \
    --cc=amit.shah@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.