It's already confusing that we have two very similar functions for
wrapping the parse of a 64-bit unsigned value, differing mainly on
whether they permit leading '-'.  Adjust the signature of parse_uint()
and parse_uint_full() to be like all of qemu_strto*(): put the result
parameter last, use the same types (uint64_t and unsigned long long
have the same width, but are not always the same type), and mark
endptr const (this latter change only affects the rare caller of
parse_uint).  Adjust all callers in the tree.
While at it, note that since cutils.c already includes:
    QEMU_BUILD_BUG_ON(sizeof(int64_t) != sizeof(long long));
we are guaranteed that the result of parse_uint* cannot exceed
UINT64_MAX (or the build would have failed), so we can drop
pre-existing dead comparisons in opts-visitor.c that were never false.
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-8-eblake@redhat.com>
[eblake: Drop dead code spotted by Markus]
Signed-off-by: Eric Blake <eblake@redhat.com>
		
	
			
		
			
				
	
	
		
			102 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			102 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * QEMU guest-visible random functions
 | 
						|
 *
 | 
						|
 * Copyright 2019 Linaro, Ltd.
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or modify it
 | 
						|
 * under the terms of the GNU General Public License as published by the Free
 | 
						|
 * Software Foundation; either version 2 of the License, or (at your option)
 | 
						|
 * any later version.
 | 
						|
 */
 | 
						|
 | 
						|
#include "qemu/osdep.h"
 | 
						|
#include "qemu/cutils.h"
 | 
						|
#include "qapi/error.h"
 | 
						|
#include "qemu/guest-random.h"
 | 
						|
#include "crypto/random.h"
 | 
						|
#include "exec/replay-core.h"
 | 
						|
 | 
						|
 | 
						|
static __thread GRand *thread_rand;
 | 
						|
static bool deterministic;
 | 
						|
 | 
						|
 | 
						|
static int glib_random_bytes(void *buf, size_t len)
 | 
						|
{
 | 
						|
    GRand *rand = thread_rand;
 | 
						|
    size_t i;
 | 
						|
    uint32_t x;
 | 
						|
 | 
						|
    if (unlikely(rand == NULL)) {
 | 
						|
        /* Thread not initialized for a cpu, or main w/o -seed.  */
 | 
						|
        thread_rand = rand = g_rand_new();
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i + 4 <= len; i += 4) {
 | 
						|
        x = g_rand_int(rand);
 | 
						|
        __builtin_memcpy(buf + i, &x, 4);
 | 
						|
    }
 | 
						|
    if (i < len) {
 | 
						|
        x = g_rand_int(rand);
 | 
						|
        __builtin_memcpy(buf + i, &x, len - i);
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int qemu_guest_getrandom(void *buf, size_t len, Error **errp)
 | 
						|
{
 | 
						|
    int ret;
 | 
						|
    if (replay_mode == REPLAY_MODE_PLAY) {
 | 
						|
        return replay_read_random(buf, len);
 | 
						|
    }
 | 
						|
    if (unlikely(deterministic)) {
 | 
						|
        /* Deterministic implementation using Glib's Mersenne Twister.  */
 | 
						|
        ret = glib_random_bytes(buf, len);
 | 
						|
    } else {
 | 
						|
        /* Non-deterministic implementation using crypto routines.  */
 | 
						|
        ret = qcrypto_random_bytes(buf, len, errp);
 | 
						|
    }
 | 
						|
    if (replay_mode == REPLAY_MODE_RECORD) {
 | 
						|
        replay_save_random(ret, buf, len);
 | 
						|
    }
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
void qemu_guest_getrandom_nofail(void *buf, size_t len)
 | 
						|
{
 | 
						|
    (void)qemu_guest_getrandom(buf, len, &error_fatal);
 | 
						|
}
 | 
						|
 | 
						|
uint64_t qemu_guest_random_seed_thread_part1(void)
 | 
						|
{
 | 
						|
    if (deterministic) {
 | 
						|
        uint64_t ret;
 | 
						|
        glib_random_bytes(&ret, sizeof(ret));
 | 
						|
        return ret;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
void qemu_guest_random_seed_thread_part2(uint64_t seed)
 | 
						|
{
 | 
						|
    g_assert(thread_rand == NULL);
 | 
						|
    if (deterministic) {
 | 
						|
        thread_rand =
 | 
						|
            g_rand_new_with_seed_array((const guint32 *)&seed,
 | 
						|
                                       sizeof(seed) / sizeof(guint32));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
int qemu_guest_random_seed_main(const char *optarg, Error **errp)
 | 
						|
{
 | 
						|
    uint64_t seed;
 | 
						|
    if (parse_uint_full(optarg, 0, &seed)) {
 | 
						|
        error_setg(errp, "Invalid seed number: %s", optarg);
 | 
						|
        return -1;
 | 
						|
    } else {
 | 
						|
        deterministic = true;
 | 
						|
        qemu_guest_random_seed_thread_part2(seed);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
}
 |