xref: /openbmc/qemu/util/guest-random.c (revision 259ebed4)
1 /*
2  * QEMU guest-visible random functions
3  *
4  * Copyright 2019 Linaro, Ltd.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 2 of the License, or (at your option)
9  * any later version.
10  */
11 
12 #include "qemu/osdep.h"
13 #include "qemu/cutils.h"
14 #include "qapi/error.h"
15 #include "qemu/guest-random.h"
16 #include "crypto/random.h"
17 #include "exec/replay-core.h"
18 
19 
20 static __thread GRand *thread_rand;
21 static bool deterministic;
22 
23 
24 static int glib_random_bytes(void *buf, size_t len)
25 {
26     GRand *rand = thread_rand;
27     size_t i;
28     uint32_t x;
29 
30     if (unlikely(rand == NULL)) {
31         /* Thread not initialized for a cpu, or main w/o -seed.  */
32         thread_rand = rand = g_rand_new();
33     }
34 
35     for (i = 0; i + 4 <= len; i += 4) {
36         x = g_rand_int(rand);
37         __builtin_memcpy(buf + i, &x, 4);
38     }
39     if (i < len) {
40         x = g_rand_int(rand);
41         __builtin_memcpy(buf + i, &x, len - i);
42     }
43     return 0;
44 }
45 
46 int qemu_guest_getrandom(void *buf, size_t len, Error **errp)
47 {
48     int ret;
49     if (replay_mode == REPLAY_MODE_PLAY) {
50         return replay_read_random(buf, len);
51     }
52     if (unlikely(deterministic)) {
53         /* Deterministic implementation using Glib's Mersenne Twister.  */
54         ret = glib_random_bytes(buf, len);
55     } else {
56         /* Non-deterministic implementation using crypto routines.  */
57         ret = qcrypto_random_bytes(buf, len, errp);
58     }
59     if (replay_mode == REPLAY_MODE_RECORD) {
60         replay_save_random(ret, buf, len);
61     }
62     return ret;
63 }
64 
65 void qemu_guest_getrandom_nofail(void *buf, size_t len)
66 {
67     (void)qemu_guest_getrandom(buf, len, &error_fatal);
68 }
69 
70 uint64_t qemu_guest_random_seed_thread_part1(void)
71 {
72     if (deterministic) {
73         uint64_t ret;
74         glib_random_bytes(&ret, sizeof(ret));
75         return ret;
76     }
77     return 0;
78 }
79 
80 void qemu_guest_random_seed_thread_part2(uint64_t seed)
81 {
82     g_assert(thread_rand == NULL);
83     if (deterministic) {
84         thread_rand =
85             g_rand_new_with_seed_array((const guint32 *)&seed,
86                                        sizeof(seed) / sizeof(guint32));
87     }
88 }
89 
90 int qemu_guest_random_seed_main(const char *seedstr, Error **errp)
91 {
92     uint64_t seed;
93     if (parse_uint_full(seedstr, 0, &seed)) {
94         error_setg(errp, "Invalid seed number: %s", seedstr);
95         return -1;
96     } else {
97         deterministic = true;
98         qemu_guest_random_seed_thread_part2(seed);
99         return 0;
100     }
101 }
102