qemu/util/guest-random.c
<<
>>
Prefs
   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
  18
  19static __thread GRand *thread_rand;
  20static bool deterministic;
  21
  22
  23static int glib_random_bytes(void *buf, size_t len)
  24{
  25    GRand *rand = thread_rand;
  26    size_t i;
  27    uint32_t x;
  28
  29    if (unlikely(rand == NULL)) {
  30        /* Thread not initialized for a cpu, or main w/o -seed.  */
  31        thread_rand = rand = g_rand_new();
  32    }
  33
  34    for (i = 0; i + 4 <= len; i += 4) {
  35        x = g_rand_int(rand);
  36        __builtin_memcpy(buf + i, &x, 4);
  37    }
  38    if (i < len) {
  39        x = g_rand_int(rand);
  40        __builtin_memcpy(buf + i, &x, i - len);
  41    }
  42    return 0;
  43}
  44
  45int qemu_guest_getrandom(void *buf, size_t len, Error **errp)
  46{
  47    if (unlikely(deterministic)) {
  48        /* Deterministic implementation using Glib's Mersenne Twister.  */
  49        return glib_random_bytes(buf, len);
  50    } else {
  51        /* Non-deterministic implementation using crypto routines.  */
  52        return qcrypto_random_bytes(buf, len, errp);
  53    }
  54}
  55
  56void qemu_guest_getrandom_nofail(void *buf, size_t len)
  57{
  58    (void)qemu_guest_getrandom(buf, len, &error_fatal);
  59}
  60
  61uint64_t qemu_guest_random_seed_thread_part1(void)
  62{
  63    if (deterministic) {
  64        uint64_t ret;
  65        glib_random_bytes(&ret, sizeof(ret));
  66        return ret;
  67    }
  68    return 0;
  69}
  70
  71void qemu_guest_random_seed_thread_part2(uint64_t seed)
  72{
  73    g_assert(thread_rand == NULL);
  74    if (deterministic) {
  75        thread_rand =
  76            g_rand_new_with_seed_array((const guint32 *)&seed,
  77                                       sizeof(seed) / sizeof(guint32));
  78    }
  79}
  80
  81int qemu_guest_random_seed_main(const char *optarg, Error **errp)
  82{
  83    unsigned long long seed;
  84    if (parse_uint_full(optarg, &seed, 0)) {
  85        error_setg(errp, "Invalid seed number: %s", optarg);
  86        return -1;
  87    } else {
  88        deterministic = true;
  89        qemu_guest_random_seed_thread_part2(seed);
  90        return 0;
  91    }
  92}
  93