18d8404f1SRichard Henderson /* 28d8404f1SRichard Henderson * QEMU guest-visible random functions 38d8404f1SRichard Henderson * 48d8404f1SRichard Henderson * Copyright 2019 Linaro, Ltd. 58d8404f1SRichard Henderson * 68d8404f1SRichard Henderson * This program is free software; you can redistribute it and/or modify it 78d8404f1SRichard Henderson * under the terms of the GNU General Public License as published by the Free 88d8404f1SRichard Henderson * Software Foundation; either version 2 of the License, or (at your option) 98d8404f1SRichard Henderson * any later version. 108d8404f1SRichard Henderson */ 118d8404f1SRichard Henderson 128d8404f1SRichard Henderson #include "qemu/osdep.h" 138d8404f1SRichard Henderson #include "qemu/cutils.h" 148d8404f1SRichard Henderson #include "qapi/error.h" 158d8404f1SRichard Henderson #include "qemu/guest-random.h" 168d8404f1SRichard Henderson #include "crypto/random.h" 17*5b5968c4SPhilippe Mathieu-Daudé #include "exec/replay-core.h" 188d8404f1SRichard Henderson 198d8404f1SRichard Henderson 208d8404f1SRichard Henderson static __thread GRand *thread_rand; 218d8404f1SRichard Henderson static bool deterministic; 228d8404f1SRichard Henderson 238d8404f1SRichard Henderson 248d8404f1SRichard Henderson static int glib_random_bytes(void *buf, size_t len) 258d8404f1SRichard Henderson { 268d8404f1SRichard Henderson GRand *rand = thread_rand; 278d8404f1SRichard Henderson size_t i; 288d8404f1SRichard Henderson uint32_t x; 298d8404f1SRichard Henderson 308d8404f1SRichard Henderson if (unlikely(rand == NULL)) { 318d8404f1SRichard Henderson /* Thread not initialized for a cpu, or main w/o -seed. */ 328d8404f1SRichard Henderson thread_rand = rand = g_rand_new(); 338d8404f1SRichard Henderson } 348d8404f1SRichard Henderson 358d8404f1SRichard Henderson for (i = 0; i + 4 <= len; i += 4) { 368d8404f1SRichard Henderson x = g_rand_int(rand); 378d8404f1SRichard Henderson __builtin_memcpy(buf + i, &x, 4); 388d8404f1SRichard Henderson } 398d8404f1SRichard Henderson if (i < len) { 408d8404f1SRichard Henderson x = g_rand_int(rand); 41e28ffe90SMark Nelson __builtin_memcpy(buf + i, &x, len - i); 428d8404f1SRichard Henderson } 438d8404f1SRichard Henderson return 0; 448d8404f1SRichard Henderson } 458d8404f1SRichard Henderson 468d8404f1SRichard Henderson int qemu_guest_getrandom(void *buf, size_t len, Error **errp) 478d8404f1SRichard Henderson { 48878ec29bSPavel Dovgalyuk int ret; 49878ec29bSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_PLAY) { 50878ec29bSPavel Dovgalyuk return replay_read_random(buf, len); 51878ec29bSPavel Dovgalyuk } 528d8404f1SRichard Henderson if (unlikely(deterministic)) { 538d8404f1SRichard Henderson /* Deterministic implementation using Glib's Mersenne Twister. */ 54878ec29bSPavel Dovgalyuk ret = glib_random_bytes(buf, len); 558d8404f1SRichard Henderson } else { 568d8404f1SRichard Henderson /* Non-deterministic implementation using crypto routines. */ 57878ec29bSPavel Dovgalyuk ret = qcrypto_random_bytes(buf, len, errp); 588d8404f1SRichard Henderson } 59878ec29bSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_RECORD) { 60878ec29bSPavel Dovgalyuk replay_save_random(ret, buf, len); 61878ec29bSPavel Dovgalyuk } 62878ec29bSPavel Dovgalyuk return ret; 638d8404f1SRichard Henderson } 648d8404f1SRichard Henderson 658d8404f1SRichard Henderson void qemu_guest_getrandom_nofail(void *buf, size_t len) 668d8404f1SRichard Henderson { 6711259e9aSRichard Henderson (void)qemu_guest_getrandom(buf, len, &error_fatal); 688d8404f1SRichard Henderson } 698d8404f1SRichard Henderson 708d8404f1SRichard Henderson uint64_t qemu_guest_random_seed_thread_part1(void) 718d8404f1SRichard Henderson { 728d8404f1SRichard Henderson if (deterministic) { 738d8404f1SRichard Henderson uint64_t ret; 748d8404f1SRichard Henderson glib_random_bytes(&ret, sizeof(ret)); 758d8404f1SRichard Henderson return ret; 768d8404f1SRichard Henderson } 778d8404f1SRichard Henderson return 0; 788d8404f1SRichard Henderson } 798d8404f1SRichard Henderson 808d8404f1SRichard Henderson void qemu_guest_random_seed_thread_part2(uint64_t seed) 818d8404f1SRichard Henderson { 828d8404f1SRichard Henderson g_assert(thread_rand == NULL); 838d8404f1SRichard Henderson if (deterministic) { 848d8404f1SRichard Henderson thread_rand = 858d8404f1SRichard Henderson g_rand_new_with_seed_array((const guint32 *)&seed, 868d8404f1SRichard Henderson sizeof(seed) / sizeof(guint32)); 878d8404f1SRichard Henderson } 888d8404f1SRichard Henderson } 898d8404f1SRichard Henderson 908d8404f1SRichard Henderson int qemu_guest_random_seed_main(const char *optarg, Error **errp) 918d8404f1SRichard Henderson { 928d8404f1SRichard Henderson unsigned long long seed; 938d8404f1SRichard Henderson if (parse_uint_full(optarg, &seed, 0)) { 948d8404f1SRichard Henderson error_setg(errp, "Invalid seed number: %s", optarg); 958d8404f1SRichard Henderson return -1; 968d8404f1SRichard Henderson } else { 978d8404f1SRichard Henderson deterministic = true; 988d8404f1SRichard Henderson qemu_guest_random_seed_thread_part2(seed); 998d8404f1SRichard Henderson return 0; 1008d8404f1SRichard Henderson } 1018d8404f1SRichard Henderson } 102