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