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-common.h" 148d8404f1SRichard Henderson #include "qemu/cutils.h" 158d8404f1SRichard Henderson #include "qapi/error.h" 168d8404f1SRichard Henderson #include "qemu/guest-random.h" 178d8404f1SRichard Henderson #include "crypto/random.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); 418d8404f1SRichard Henderson __builtin_memcpy(buf + i, &x, i - len); 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 { 488d8404f1SRichard Henderson if (unlikely(deterministic)) { 498d8404f1SRichard Henderson /* Deterministic implementation using Glib's Mersenne Twister. */ 508d8404f1SRichard Henderson return glib_random_bytes(buf, len); 518d8404f1SRichard Henderson } else { 528d8404f1SRichard Henderson /* Non-deterministic implementation using crypto routines. */ 538d8404f1SRichard Henderson return qcrypto_random_bytes(buf, len, errp); 548d8404f1SRichard Henderson } 558d8404f1SRichard Henderson } 568d8404f1SRichard Henderson 578d8404f1SRichard Henderson void qemu_guest_getrandom_nofail(void *buf, size_t len) 588d8404f1SRichard Henderson { 59*11259e9aSRichard Henderson (void)qemu_guest_getrandom(buf, len, &error_fatal); 608d8404f1SRichard Henderson } 618d8404f1SRichard Henderson 628d8404f1SRichard Henderson uint64_t qemu_guest_random_seed_thread_part1(void) 638d8404f1SRichard Henderson { 648d8404f1SRichard Henderson if (deterministic) { 658d8404f1SRichard Henderson uint64_t ret; 668d8404f1SRichard Henderson glib_random_bytes(&ret, sizeof(ret)); 678d8404f1SRichard Henderson return ret; 688d8404f1SRichard Henderson } 698d8404f1SRichard Henderson return 0; 708d8404f1SRichard Henderson } 718d8404f1SRichard Henderson 728d8404f1SRichard Henderson void qemu_guest_random_seed_thread_part2(uint64_t seed) 738d8404f1SRichard Henderson { 748d8404f1SRichard Henderson g_assert(thread_rand == NULL); 758d8404f1SRichard Henderson if (deterministic) { 768d8404f1SRichard Henderson thread_rand = 778d8404f1SRichard Henderson g_rand_new_with_seed_array((const guint32 *)&seed, 788d8404f1SRichard Henderson sizeof(seed) / sizeof(guint32)); 798d8404f1SRichard Henderson } 808d8404f1SRichard Henderson } 818d8404f1SRichard Henderson 828d8404f1SRichard Henderson int qemu_guest_random_seed_main(const char *optarg, Error **errp) 838d8404f1SRichard Henderson { 848d8404f1SRichard Henderson unsigned long long seed; 858d8404f1SRichard Henderson if (parse_uint_full(optarg, &seed, 0)) { 868d8404f1SRichard Henderson error_setg(errp, "Invalid seed number: %s", optarg); 878d8404f1SRichard Henderson return -1; 888d8404f1SRichard Henderson } else { 898d8404f1SRichard Henderson deterministic = true; 908d8404f1SRichard Henderson qemu_guest_random_seed_thread_part2(seed); 918d8404f1SRichard Henderson return 0; 928d8404f1SRichard Henderson } 938d8404f1SRichard Henderson } 94