qemu/backends/rng-random.c
<<
>>
Prefs
   1/*
   2 * QEMU Random Number Generator Backend
   3 *
   4 * Copyright IBM, Corp. 2012
   5 *
   6 * Authors:
   7 *  Anthony Liguori   <aliguori@us.ibm.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 */
  12
  13#include "qemu/osdep.h"
  14#include "sysemu/rng-random.h"
  15#include "sysemu/rng.h"
  16#include "qapi/error.h"
  17#include "qapi/qmp/qerror.h"
  18#include "qemu/main-loop.h"
  19#include "qemu/module.h"
  20
  21struct RngRandom
  22{
  23    RngBackend parent;
  24
  25    int fd;
  26    char *filename;
  27};
  28
  29/**
  30 * A simple and incomplete backend to request entropy from /dev/random.
  31 *
  32 * This backend exposes an additional "filename" property that can be used to
  33 * set the filename to use to open the backend.
  34 */
  35
  36static void entropy_available(void *opaque)
  37{
  38    RngRandom *s = RNG_RANDOM(opaque);
  39
  40    while (!QSIMPLEQ_EMPTY(&s->parent.requests)) {
  41        RngRequest *req = QSIMPLEQ_FIRST(&s->parent.requests);
  42        ssize_t len;
  43
  44        len = read(s->fd, req->data, req->size);
  45        if (len < 0 && errno == EAGAIN) {
  46            return;
  47        }
  48        g_assert(len != -1);
  49
  50        req->receive_entropy(req->opaque, req->data, len);
  51
  52        rng_backend_finalize_request(&s->parent, req);
  53    }
  54
  55    /* We've drained all requests, the fd handler can be reset. */
  56    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
  57}
  58
  59static void rng_random_request_entropy(RngBackend *b, RngRequest *req)
  60{
  61    RngRandom *s = RNG_RANDOM(b);
  62
  63    if (QSIMPLEQ_EMPTY(&s->parent.requests)) {
  64        /* If there are no pending requests yet, we need to
  65         * install our fd handler. */
  66        qemu_set_fd_handler(s->fd, entropy_available, NULL, s);
  67    }
  68}
  69
  70static void rng_random_opened(RngBackend *b, Error **errp)
  71{
  72    RngRandom *s = RNG_RANDOM(b);
  73
  74    if (s->filename == NULL) {
  75        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
  76                   "filename", "a valid filename");
  77    } else {
  78        s->fd = qemu_open_old(s->filename, O_RDONLY | O_NONBLOCK);
  79        if (s->fd == -1) {
  80            error_setg_file_open(errp, errno, s->filename);
  81        }
  82    }
  83}
  84
  85static char *rng_random_get_filename(Object *obj, Error **errp)
  86{
  87    RngRandom *s = RNG_RANDOM(obj);
  88
  89    return g_strdup(s->filename);
  90}
  91
  92static void rng_random_set_filename(Object *obj, const char *filename,
  93                                 Error **errp)
  94{
  95    RngBackend *b = RNG_BACKEND(obj);
  96    RngRandom *s = RNG_RANDOM(obj);
  97
  98    if (b->opened) {
  99        error_setg(errp, QERR_PERMISSION_DENIED);
 100        return;
 101    }
 102
 103    g_free(s->filename);
 104    s->filename = g_strdup(filename);
 105}
 106
 107static void rng_random_init(Object *obj)
 108{
 109    RngRandom *s = RNG_RANDOM(obj);
 110
 111    s->filename = g_strdup("/dev/urandom");
 112    s->fd = -1;
 113}
 114
 115static void rng_random_finalize(Object *obj)
 116{
 117    RngRandom *s = RNG_RANDOM(obj);
 118
 119    if (s->fd != -1) {
 120        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
 121        qemu_close(s->fd);
 122    }
 123
 124    g_free(s->filename);
 125}
 126
 127static void rng_random_class_init(ObjectClass *klass, void *data)
 128{
 129    RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
 130
 131    rbc->request_entropy = rng_random_request_entropy;
 132    rbc->opened = rng_random_opened;
 133    object_class_property_add_str(klass, "filename",
 134                                  rng_random_get_filename,
 135                                  rng_random_set_filename);
 136
 137}
 138
 139static const TypeInfo rng_random_info = {
 140    .name = TYPE_RNG_RANDOM,
 141    .parent = TYPE_RNG_BACKEND,
 142    .instance_size = sizeof(RngRandom),
 143    .class_init = rng_random_class_init,
 144    .instance_init = rng_random_init,
 145    .instance_finalize = rng_random_finalize,
 146};
 147
 148static void register_types(void)
 149{
 150    type_register_static(&rng_random_info);
 151}
 152
 153type_init(register_types);
 154