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