blob: 33607d5ff24d0ace1ddec5fc90dc11235234d866 [file] [log] [blame]
Richard Henderson8d8404f2019-03-14 13:02:09 -07001/*
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"
Richard Henderson8d8404f2019-03-14 13:02:09 -070013#include "qemu/cutils.h"
14#include "qapi/error.h"
15#include "qemu/guest-random.h"
16#include "crypto/random.h"
Philippe Mathieu-Daudé5b5968c2022-12-19 18:09:43 +010017#include "exec/replay-core.h"
Richard Henderson8d8404f2019-03-14 13:02:09 -070018
19
20static __thread GRand *thread_rand;
21static bool deterministic;
22
23
24static 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);
Mark Nelsone28ffe92021-07-09 07:06:00 -050041 __builtin_memcpy(buf + i, &x, len - i);
Richard Henderson8d8404f2019-03-14 13:02:09 -070042 }
43 return 0;
44}
45
46int qemu_guest_getrandom(void *buf, size_t len, Error **errp)
47{
Pavel Dovgalyuk878ec292019-12-19 15:50:48 +030048 int ret;
49 if (replay_mode == REPLAY_MODE_PLAY) {
50 return replay_read_random(buf, len);
51 }
Richard Henderson8d8404f2019-03-14 13:02:09 -070052 if (unlikely(deterministic)) {
53 /* Deterministic implementation using Glib's Mersenne Twister. */
Pavel Dovgalyuk878ec292019-12-19 15:50:48 +030054 ret = glib_random_bytes(buf, len);
Richard Henderson8d8404f2019-03-14 13:02:09 -070055 } else {
56 /* Non-deterministic implementation using crypto routines. */
Pavel Dovgalyuk878ec292019-12-19 15:50:48 +030057 ret = qcrypto_random_bytes(buf, len, errp);
Richard Henderson8d8404f2019-03-14 13:02:09 -070058 }
Pavel Dovgalyuk878ec292019-12-19 15:50:48 +030059 if (replay_mode == REPLAY_MODE_RECORD) {
60 replay_save_random(ret, buf, len);
61 }
62 return ret;
Richard Henderson8d8404f2019-03-14 13:02:09 -070063}
64
65void qemu_guest_getrandom_nofail(void *buf, size_t len)
66{
Richard Henderson11259e92019-05-30 12:38:24 -050067 (void)qemu_guest_getrandom(buf, len, &error_fatal);
Richard Henderson8d8404f2019-03-14 13:02:09 -070068}
69
70uint64_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
80void 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
Philippe Mathieu-Daudéca84e7b2023-10-04 14:00:15 +020090int qemu_guest_random_seed_main(const char *seedstr, Error **errp)
Richard Henderson8d8404f2019-03-14 13:02:09 -070091{
Eric Blakebd1386c2023-05-22 14:04:29 -050092 uint64_t seed;
Philippe Mathieu-Daudéca84e7b2023-10-04 14:00:15 +020093 if (parse_uint_full(seedstr, 0, &seed)) {
94 error_setg(errp, "Invalid seed number: %s", seedstr);
Richard Henderson8d8404f2019-03-14 13:02:09 -070095 return -1;
96 } else {
97 deterministic = true;
98 qemu_guest_random_seed_thread_part2(seed);
99 return 0;
100 }
101}