xref: /openbmc/qemu/backends/rng-random.c (revision 5c74521d249486fa3e749dbbf6d56a70d4d7235f)
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