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