xref: /openbmc/qemu/util/guest-random.c (revision ab9056ff)
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 
18 
19 static __thread GRand *thread_rand;
20 static bool deterministic;
21 
22 
23 static int glib_random_bytes(void *buf, size_t len)
24 {
25     GRand *rand = thread_rand;
26     size_t i;
27     uint32_t x;
28 
29     if (unlikely(rand == NULL)) {
30         /* Thread not initialized for a cpu, or main w/o -seed.  */
31         thread_rand = rand = g_rand_new();
32     }
33 
34     for (i = 0; i + 4 <= len; i += 4) {
35         x = g_rand_int(rand);
36         __builtin_memcpy(buf + i, &x, 4);
37     }
38     if (i < len) {
39         x = g_rand_int(rand);
40         __builtin_memcpy(buf + i, &x, i - len);
41     }
42     return 0;
43 }
44 
45 int qemu_guest_getrandom(void *buf, size_t len, Error **errp)
46 {
47     if (unlikely(deterministic)) {
48         /* Deterministic implementation using Glib's Mersenne Twister.  */
49         return glib_random_bytes(buf, len);
50     } else {
51         /* Non-deterministic implementation using crypto routines.  */
52         return qcrypto_random_bytes(buf, len, errp);
53     }
54 }
55 
56 void qemu_guest_getrandom_nofail(void *buf, size_t len)
57 {
58     (void)qemu_guest_getrandom(buf, len, &error_fatal);
59 }
60 
61 uint64_t qemu_guest_random_seed_thread_part1(void)
62 {
63     if (deterministic) {
64         uint64_t ret;
65         glib_random_bytes(&ret, sizeof(ret));
66         return ret;
67     }
68     return 0;
69 }
70 
71 void qemu_guest_random_seed_thread_part2(uint64_t seed)
72 {
73     g_assert(thread_rand == NULL);
74     if (deterministic) {
75         thread_rand =
76             g_rand_new_with_seed_array((const guint32 *)&seed,
77                                        sizeof(seed) / sizeof(guint32));
78     }
79 }
80 
81 int qemu_guest_random_seed_main(const char *optarg, Error **errp)
82 {
83     unsigned long long seed;
84     if (parse_uint_full(optarg, &seed, 0)) {
85         error_setg(errp, "Invalid seed number: %s", optarg);
86         return -1;
87     } else {
88         deterministic = true;
89         qemu_guest_random_seed_thread_part2(seed);
90         return 0;
91     }
92 }
93