Richard Henderson | 8d8404f | 2019-03-14 13:02:09 -0700 | [diff] [blame] | 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" |
Richard Henderson | 8d8404f | 2019-03-14 13:02:09 -0700 | [diff] [blame] | 13 | #include "qemu/cutils.h" |
| 14 | #include "qapi/error.h" |
| 15 | #include "qemu/guest-random.h" |
| 16 | #include "crypto/random.h" |
Philippe Mathieu-Daudé | 5b5968c | 2022-12-19 18:09:43 +0100 | [diff] [blame] | 17 | #include "exec/replay-core.h" |
Richard Henderson | 8d8404f | 2019-03-14 13:02:09 -0700 | [diff] [blame] | 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); |
Mark Nelson | e28ffe9 | 2021-07-09 07:06:00 -0500 | [diff] [blame] | 41 | __builtin_memcpy(buf + i, &x, len - i); |
Richard Henderson | 8d8404f | 2019-03-14 13:02:09 -0700 | [diff] [blame] | 42 | } |
| 43 | return 0; |
| 44 | } |
| 45 | |
| 46 | int qemu_guest_getrandom(void *buf, size_t len, Error **errp) |
| 47 | { |
Pavel Dovgalyuk | 878ec29 | 2019-12-19 15:50:48 +0300 | [diff] [blame] | 48 | int ret; |
| 49 | if (replay_mode == REPLAY_MODE_PLAY) { |
| 50 | return replay_read_random(buf, len); |
| 51 | } |
Richard Henderson | 8d8404f | 2019-03-14 13:02:09 -0700 | [diff] [blame] | 52 | if (unlikely(deterministic)) { |
| 53 | /* Deterministic implementation using Glib's Mersenne Twister. */ |
Pavel Dovgalyuk | 878ec29 | 2019-12-19 15:50:48 +0300 | [diff] [blame] | 54 | ret = glib_random_bytes(buf, len); |
Richard Henderson | 8d8404f | 2019-03-14 13:02:09 -0700 | [diff] [blame] | 55 | } else { |
| 56 | /* Non-deterministic implementation using crypto routines. */ |
Pavel Dovgalyuk | 878ec29 | 2019-12-19 15:50:48 +0300 | [diff] [blame] | 57 | ret = qcrypto_random_bytes(buf, len, errp); |
Richard Henderson | 8d8404f | 2019-03-14 13:02:09 -0700 | [diff] [blame] | 58 | } |
Pavel Dovgalyuk | 878ec29 | 2019-12-19 15:50:48 +0300 | [diff] [blame] | 59 | if (replay_mode == REPLAY_MODE_RECORD) { |
| 60 | replay_save_random(ret, buf, len); |
| 61 | } |
| 62 | return ret; |
Richard Henderson | 8d8404f | 2019-03-14 13:02:09 -0700 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | void qemu_guest_getrandom_nofail(void *buf, size_t len) |
| 66 | { |
Richard Henderson | 11259e9 | 2019-05-30 12:38:24 -0500 | [diff] [blame] | 67 | (void)qemu_guest_getrandom(buf, len, &error_fatal); |
Richard Henderson | 8d8404f | 2019-03-14 13:02:09 -0700 | [diff] [blame] | 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 | |
Philippe Mathieu-Daudé | ca84e7b | 2023-10-04 14:00:15 +0200 | [diff] [blame] | 90 | int qemu_guest_random_seed_main(const char *seedstr, Error **errp) |
Richard Henderson | 8d8404f | 2019-03-14 13:02:09 -0700 | [diff] [blame] | 91 | { |
Eric Blake | bd1386c | 2023-05-22 14:04:29 -0500 | [diff] [blame] | 92 | uint64_t seed; |
Philippe Mathieu-Daudé | ca84e7b | 2023-10-04 14:00:15 +0200 | [diff] [blame] | 93 | if (parse_uint_full(seedstr, 0, &seed)) { |
| 94 | error_setg(errp, "Invalid seed number: %s", seedstr); |
Richard Henderson | 8d8404f | 2019-03-14 13:02:09 -0700 | [diff] [blame] | 95 | return -1; |
| 96 | } else { |
| 97 | deterministic = true; |
| 98 | qemu_guest_random_seed_thread_part2(seed); |
| 99 | return 0; |
| 100 | } |
| 101 | } |