]>
Commit | Line | Data |
---|---|---|
8d8404f1 RH |
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" | |
8d8404f1 RH |
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 | { | |
11259e9a | 58 | (void)qemu_guest_getrandom(buf, len, &error_fatal); |
8d8404f1 RH |
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 | } |