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 #include "exec/replay-core.h" 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); 41 __builtin_memcpy(buf + i, &x, len - i); 42 } 43 return 0; 44 } 45 46 int qemu_guest_getrandom(void *buf, size_t len, Error **errp) 47 { 48 int ret; 49 if (replay_mode == REPLAY_MODE_PLAY) { 50 return replay_read_random(buf, len); 51 } 52 if (unlikely(deterministic)) { 53 /* Deterministic implementation using Glib's Mersenne Twister. */ 54 ret = glib_random_bytes(buf, len); 55 } else { 56 /* Non-deterministic implementation using crypto routines. */ 57 ret = qcrypto_random_bytes(buf, len, errp); 58 } 59 if (replay_mode == REPLAY_MODE_RECORD) { 60 replay_save_random(ret, buf, len); 61 } 62 return ret; 63 } 64 65 void qemu_guest_getrandom_nofail(void *buf, size_t len) 66 { 67 (void)qemu_guest_getrandom(buf, len, &error_fatal); 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 90 int qemu_guest_random_seed_main(const char *optarg, Error **errp) 91 { 92 uint64_t seed; 93 if (parse_uint_full(optarg, 0, &seed)) { 94 error_setg(errp, "Invalid seed number: %s", optarg); 95 return -1; 96 } else { 97 deterministic = true; 98 qemu_guest_random_seed_thread_part2(seed); 99 return 0; 100 } 101 } 102