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 "sysemu/rng-random.h"
  14#include "sysemu/rng.h"
  15#include "qapi/qmp/qerror.h"
  16#include "qemu/main-loop.h"
  17
  18struct RndRandom
  19{
  20    RngBackend parent;
  21
  22    int fd;
  23    char *filename;
  24
  25    EntropyReceiveFunc *receive_func;
  26    void *opaque;
  27    size_t size;
  28};
  29
  30/**
  31 * A simple and incomplete backend to request entropy from /dev/random.
  32 *
  33 * This backend exposes an additional "filename" property that can be used to
  34 * set the filename to use to open the backend.
  35 */
  36
  37static void entropy_available(void *opaque)
  38{
  39    RndRandom *s = RNG_RANDOM(opaque);
  40    uint8_t buffer[s->size];
  41    ssize_t len;
  42
  43    len = read(s->fd, buffer, s->size);
  44    if (len < 0 && errno == EAGAIN) {
  45        return;
  46    }
  47    g_assert(len != -1);
  48
  49    s->receive_func(s->opaque, buffer, len);
  50    s->receive_func = NULL;
  51
  52    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
  53}
  54
  55static void rng_random_request_entropy(RngBackend *b, size_t size,
  56                                        EntropyReceiveFunc *receive_entropy,
  57                                        void *opaque)
  58{
  59    RndRandom *s = RNG_RANDOM(b);
  60
  61    if (s->receive_func) {
  62        s->receive_func(s->opaque, NULL, 0);
  63    }
  64
  65    s->receive_func = receive_entropy;
  66    s->opaque = opaque;
  67    s->size = size;
  68
  69    qemu_set_fd_handler(s->fd, entropy_available, NULL, s);
  70}
  71
  72static void rng_random_opened(RngBackend *b, Error **errp)
  73{
  74    RndRandom *s = RNG_RANDOM(b);
  75
  76    if (s->filename == NULL) {
  77        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
  78                   "filename", "a valid filename");
  79    } else {
  80        s->fd = qemu_open(s->filename, O_RDONLY | O_NONBLOCK);
  81        if (s->fd == -1) {
  82            error_setg_file_open(errp, errno, s->filename);
  83        }
  84    }
  85}
  86
  87static char *rng_random_get_filename(Object *obj, Error **errp)
  88{
  89    RndRandom *s = RNG_RANDOM(obj);
  90
  91    return g_strdup(s->filename);
  92}
  93
  94static void rng_random_set_filename(Object *obj, const char *filename,
  95                                 Error **errp)
  96{
  97    RngBackend *b = RNG_BACKEND(obj);
  98    RndRandom *s = RNG_RANDOM(obj);
  99
 100    if (b->opened) {
 101        error_setg(errp, QERR_PERMISSION_DENIED);
 102        return;
 103    }
 104
 105    g_free(s->filename);
 106    s->filename = g_strdup(filename);
 107}
 108
 109static void rng_random_init(Object *obj)
 110{
 111    RndRandom *s = RNG_RANDOM(obj);
 112
 113    object_property_add_str(obj, "filename",
 114                            rng_random_get_filename,
 115                            rng_random_set_filename,
 116                            NULL);
 117
 118    s->filename = g_strdup("/dev/random");
 119    s->fd = -1;
 120}
 121
 122static void rng_random_finalize(Object *obj)
 123{
 124    RndRandom *s = RNG_RANDOM(obj);
 125
 126    if (s->fd != -1) {
 127        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
 128        qemu_close(s->fd);
 129    }
 130
 131    g_free(s->filename);
 132}
 133
 134static void rng_random_class_init(ObjectClass *klass, void *data)
 135{
 136    RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
 137
 138    rbc->request_entropy = rng_random_request_entropy;
 139    rbc->opened = rng_random_opened;
 140}
 141
 142static const TypeInfo rng_random_info = {
 143    .name = TYPE_RNG_RANDOM,
 144    .parent = TYPE_RNG_BACKEND,
 145    .instance_size = sizeof(RndRandom),
 146    .class_init = rng_random_class_init,
 147    .instance_init = rng_random_init,
 148    .instance_finalize = rng_random_finalize,
 149};
 150
 151static void register_types(void)
 152{
 153    type_register_static(&rng_random_info);
 154}
 155
 156type_init(register_types);
 157