qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

guest-random.c (2578B)


      1 /*
      2  * QEMU guest-visible random functions
      3  *
      4  * Copyright 2019 Linaro, Ltd.
      5  *
      6  * This program is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License as published by the Free
      8  * Software Foundation; either version 2 of the License, or (at your option)
      9  * any later version.
     10  */
     11 
     12 #include "qemu/osdep.h"
     13 #include "qemu/cutils.h"
     14 #include "qapi/error.h"
     15 #include "qemu/guest-random.h"
     16 #include "crypto/random.h"
     17 #include "sysemu/replay.h"
     18 
     19 
     20 static __thread GRand *thread_rand;
     21 static bool deterministic;
     22 
     23 
     24 static int glib_random_bytes(void *buf, size_t len)
     25 {
     26     GRand *rand = thread_rand;
     27     size_t i;
     28     uint32_t x;
     29 
     30     if (unlikely(rand == NULL)) {
     31         /* Thread not initialized for a cpu, or main w/o -seed.  */
     32         thread_rand = rand = g_rand_new();
     33     }
     34 
     35     for (i = 0; i + 4 <= len; i += 4) {
     36         x = g_rand_int(rand);
     37         __builtin_memcpy(buf + i, &x, 4);
     38     }
     39     if (i < len) {
     40         x = g_rand_int(rand);
     41         __builtin_memcpy(buf + i, &x, len - i);
     42     }
     43     return 0;
     44 }
     45 
     46 int qemu_guest_getrandom(void *buf, size_t len, Error **errp)
     47 {
     48     int ret;
     49     if (replay_mode == REPLAY_MODE_PLAY) {
     50         return replay_read_random(buf, len);
     51     }
     52     if (unlikely(deterministic)) {
     53         /* Deterministic implementation using Glib's Mersenne Twister.  */
     54         ret = glib_random_bytes(buf, len);
     55     } else {
     56         /* Non-deterministic implementation using crypto routines.  */
     57         ret = qcrypto_random_bytes(buf, len, errp);
     58     }
     59     if (replay_mode == REPLAY_MODE_RECORD) {
     60         replay_save_random(ret, buf, len);
     61     }
     62     return ret;
     63 }
     64 
     65 void qemu_guest_getrandom_nofail(void *buf, size_t len)
     66 {
     67     (void)qemu_guest_getrandom(buf, len, &error_fatal);
     68 }
     69 
     70 uint64_t qemu_guest_random_seed_thread_part1(void)
     71 {
     72     if (deterministic) {
     73         uint64_t ret;
     74         glib_random_bytes(&ret, sizeof(ret));
     75         return ret;
     76     }
     77     return 0;
     78 }
     79 
     80 void qemu_guest_random_seed_thread_part2(uint64_t seed)
     81 {
     82     g_assert(thread_rand == NULL);
     83     if (deterministic) {
     84         thread_rand =
     85             g_rand_new_with_seed_array((const guint32 *)&seed,
     86                                        sizeof(seed) / sizeof(guint32));
     87     }
     88 }
     89 
     90 int qemu_guest_random_seed_main(const char *optarg, Error **errp)
     91 {
     92     unsigned long long seed;
     93     if (parse_uint_full(optarg, &seed, 0)) {
     94         error_setg(errp, "Invalid seed number: %s", optarg);
     95         return -1;
     96     } else {
     97         deterministic = true;
     98         qemu_guest_random_seed_thread_part2(seed);
     99         return 0;
    100     }
    101 }