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/rng-random.h"
  14#include "qemu/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    g_assert(len != -1);
  45
  46    s->receive_func(s->opaque, buffer, len);
  47    s->receive_func = NULL;
  48
  49    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
  50}
  51
  52static void rng_random_request_entropy(RngBackend *b, size_t size,
  53                                        EntropyReceiveFunc *receive_entropy,
  54                                        void *opaque)
  55{
  56    RndRandom *s = RNG_RANDOM(b);
  57
  58    if (s->receive_func) {
  59        s->receive_func(s->opaque, NULL, 0);
  60    }
  61
  62    s->receive_func = receive_entropy;
  63    s->opaque = opaque;
  64    s->size = size;
  65
  66    qemu_set_fd_handler(s->fd, entropy_available, NULL, s);
  67}
  68
  69static void rng_random_opened(RngBackend *b, Error **errp)
  70{
  71    RndRandom *s = RNG_RANDOM(b);
  72
  73    if (s->filename == NULL) {
  74        error_set(errp, QERR_INVALID_PARAMETER_VALUE,
  75                  "filename", "a valid filename");
  76    } else {
  77        s->fd = open(s->filename, O_RDONLY | O_NONBLOCK);
  78
  79        if (s->fd == -1) {
  80            error_set(errp, QERR_OPEN_FILE_FAILED, s->filename);
  81        }
  82    }
  83}
  84
  85static char *rng_random_get_filename(Object *obj, Error **errp)
  86{
  87    RndRandom *s = RNG_RANDOM(obj);
  88
  89    if (s->filename) {
  90        return g_strdup(s->filename);
  91    }
  92
  93    return NULL;
  94}
  95
  96static void rng_random_set_filename(Object *obj, const char *filename,
  97                                 Error **errp)
  98{
  99    RngBackend *b = RNG_BACKEND(obj);
 100    RndRandom *s = RNG_RANDOM(obj);
 101
 102    if (b->opened) {
 103        error_set(errp, QERR_PERMISSION_DENIED);
 104        return;
 105    }
 106
 107    if (s->filename) {
 108        g_free(s->filename);
 109    }
 110
 111    s->filename = g_strdup(filename);
 112}
 113
 114static void rng_random_init(Object *obj)
 115{
 116    RndRandom *s = RNG_RANDOM(obj);
 117
 118    object_property_add_str(obj, "filename",
 119                            rng_random_get_filename,
 120                            rng_random_set_filename,
 121                            NULL);
 122
 123    s->filename = g_strdup("/dev/random");
 124}
 125
 126static void rng_random_finalize(Object *obj)
 127{
 128    RndRandom *s = RNG_RANDOM(obj);
 129
 130    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
 131
 132    if (s->fd != -1) {
 133        close(s->fd);
 134    }
 135
 136    g_free(s->filename);
 137}
 138
 139static void rng_random_class_init(ObjectClass *klass, void *data)
 140{
 141    RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
 142
 143    rbc->request_entropy = rng_random_request_entropy;
 144    rbc->opened = rng_random_opened;
 145}
 146
 147static const TypeInfo rng_random_info = {
 148    .name = TYPE_RNG_RANDOM,
 149    .parent = TYPE_RNG_BACKEND,
 150    .instance_size = sizeof(RndRandom),
 151    .class_init = rng_random_class_init,
 152    .instance_init = rng_random_init,
 153    .instance_finalize = rng_random_finalize,
 154};
 155
 156static void register_types(void)
 157{
 158    type_register_static(&rng_random_info);
 159}
 160
 161type_init(register_types);
 162