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"
175b5968c4SPhilippe 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
glib_random_bytes(void * buf,size_t len)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
qemu_guest_getrandom(void * buf,size_t len,Error ** errp)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
qemu_guest_getrandom_nofail(void * buf,size_t len)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
qemu_guest_random_seed_thread_part1(void)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
qemu_guest_random_seed_thread_part2(uint64_t seed)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
qemu_guest_random_seed_main(const char * seedstr,Error ** errp)90*ca84e7b2SPhilippe Mathieu-Daudé int qemu_guest_random_seed_main(const char *seedstr, Error **errp)
918d8404f1SRichard Henderson {
92bd1386ccSEric Blake uint64_t seed;
93*ca84e7b2SPhilippe Mathieu-Daudé if (parse_uint_full(seedstr, 0, &seed)) {
94*ca84e7b2SPhilippe Mathieu-Daudé error_setg(errp, "Invalid seed number: %s", seedstr);
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