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 | |