xref: /openbmc/qemu/util/guest-random.c (revision ca84e7b2)
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