xref: /openbmc/qemu/util/guest-random.c (revision 17a319b175a57ee6fde4dabcaa2e11d47c39301e)
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 "exec/replay-core.h"
18  
19  
20  static __thread GRand *thread_rand;
21  static bool deterministic;
22  
23  
glib_random_bytes(void * buf,size_t len)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  
qemu_guest_getrandom(void * buf,size_t len,Error ** errp)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  
qemu_guest_getrandom_nofail(void * buf,size_t len)65  void qemu_guest_getrandom_nofail(void *buf, size_t len)
66  {
67      (void)qemu_guest_getrandom(buf, len, &error_fatal);
68  }
69  
qemu_guest_random_seed_thread_part1(void)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  
qemu_guest_random_seed_thread_part2(uint64_t seed)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  
qemu_guest_random_seed_main(const char * seedstr,Error ** errp)90  int qemu_guest_random_seed_main(const char *seedstr, Error **errp)
91  {
92      uint64_t seed;
93      if (parse_uint_full(seedstr, 0, &seed)) {
94          error_setg(errp, "Invalid seed number: %s", seedstr);
95          return -1;
96      } else {
97          deterministic = true;
98          qemu_guest_random_seed_thread_part2(seed);
99          return 0;
100      }
101  }
102