Message ID | 20190315032629.21234-10-richard.henderson@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | Add qemu_getrandom and ARMv8.5-RNG etc | expand |
On Thu, Mar 14, 2019 at 08:26:15PM -0700, Richard Henderson wrote: > This routine is intended to produce high-quality random numbers to the > guest. Normally, such numbers are crypto quality from the host, but a > command-line option can force the use of a fully deterministic sequence > for use while debugging. > > Cc: Daniel P. Berrangé <berrange@redhat.com> > Signed-off-by: Richard Henderson <richard.henderson@linaro.org> > --- > include/qemu/guest-random.h | 68 +++++++++++++++++++++++++++ > util/guest-random.c | 93 +++++++++++++++++++++++++++++++++++++ > util/Makefile.objs | 1 + > 3 files changed, 162 insertions(+) > create mode 100644 include/qemu/guest-random.h > create mode 100644 util/guest-random.c Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
On 3/15/19 4:26 AM, Richard Henderson wrote: > This routine is intended to produce high-quality random numbers to the > guest. Normally, such numbers are crypto quality from the host, but a > command-line option can force the use of a fully deterministic sequence > for use while debugging. > > Cc: Daniel P. Berrangé <berrange@redhat.com> > Signed-off-by: Richard Henderson <richard.henderson@linaro.org> > --- > include/qemu/guest-random.h | 68 +++++++++++++++++++++++++++ > util/guest-random.c | 93 +++++++++++++++++++++++++++++++++++++ > util/Makefile.objs | 1 + > 3 files changed, 162 insertions(+) > create mode 100644 include/qemu/guest-random.h > create mode 100644 util/guest-random.c > > diff --git a/include/qemu/guest-random.h b/include/qemu/guest-random.h > new file mode 100644 > index 0000000000..09ff9c2236 > --- /dev/null > +++ b/include/qemu/guest-random.h > @@ -0,0 +1,68 @@ > +/* > + * 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. > + */ > + > +#ifndef QEMU_GUEST_RANDOM_H > +#define QEMU_GUEST_RANDOM_H > + > +/** > + * qemu_guest_random_seed_main(const char *optarg, Error **errp) > + * @optarg: a non-NULL pointer to a C string > + * @errp: an error indicator > + * > + * The @optarg value is that which accompanies the -seed argument. > + * This forces qemu_guest_getrandom into deterministic mode. > + * > + * Returns 0 on success, < 0 on failure while setting *errp. > + */ > +int qemu_guest_random_seed_main(const char *optarg, Error **errp); > + > +/** > + * qemu_guest_random_seed_thread_part1(void) > + * > + * If qemu_getrandom is in deterministic mode, returns an > + * independent seed for the new thread. Otherwise returns 0. > + */ > +uint64_t qemu_guest_random_seed_thread_part1(void); > + > +/** > + * qemu_guest_random_seed_thread_part2(uint64_t seed) > + * @seed: a value for the new thread. > + * > + * If qemu_guest_getrandom is in deterministic mode, this stores an > + * independent seed for the new thread. Otherwise a no-op. > + */ > +void qemu_guest_random_seed_thread_part2(uint64_t seed); > + > +/** > + * qemu_guest_getrandom(void *buf, size_t len, Error **errp) > + * @buf: a buffer of bytes to be written > + * @len: the number of bytes in @buf > + * @errp: an error indicator > + * > + * Fills len bytes in buf with random data. This should only be used > + * for data presented to the guest. Host-side crypto services should > + * use qcrypto_random_bytes. > + * > + * Returns 0 on success, < 0 on failure while setting *errp. > + */ > +int qemu_guest_getrandom(void *buf, size_t len, Error **errp); > + > +/** > + * qemu_guest_getrandom_nofail(void *buf, size_t len) > + * @buf: a buffer of bytes to be written > + * @len: the number of bytes in @buf API documentation appreciated, thanks! Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> > + * > + * Like qemu_guest_getrandom, but will assert for failure. > + * Use this when there is no reasonable recovery. > + */ > +void qemu_guest_getrandom_nofail(void *buf, size_t len); > + > +#endif /* QEMU_GUEST_RANDOM_H */ > diff --git a/util/guest-random.c b/util/guest-random.c > new file mode 100644 > index 0000000000..e8124a3cad > --- /dev/null > +++ b/util/guest-random.c > @@ -0,0 +1,93 @@ > +/* > + * 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-common.h" > +#include "qemu/cutils.h" > +#include "qapi/error.h" > +#include "qemu/guest-random.h" > +#include "crypto/random.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, i - len); > + } > + return 0; > +} > + > +int qemu_guest_getrandom(void *buf, size_t len, Error **errp) > +{ > + if (unlikely(deterministic)) { > + /* Deterministic implementation using Glib's Mersenne Twister. */ > + return glib_random_bytes(buf, len); > + } else { > + /* Non-deterministic implementation using crypto routines. */ > + return qcrypto_random_bytes(buf, len, errp); > + } > +} > + > +void qemu_guest_getrandom_nofail(void *buf, size_t len) > +{ > + 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) > +{ > + unsigned long long seed; > + if (parse_uint_full(optarg, &seed, 0)) { > + error_setg(errp, "Invalid seed number: %s", optarg); > + return -1; > + } else { > + deterministic = true; > + qemu_guest_random_seed_thread_part2(seed); > + return 0; > + } > +} > diff --git a/util/Makefile.objs b/util/Makefile.objs > index 835fcd69e2..4d4db653cc 100644 > --- a/util/Makefile.objs > +++ b/util/Makefile.objs > @@ -53,5 +53,6 @@ util-obj-y += iova-tree.o > util-obj-$(CONFIG_INOTIFY1) += filemonitor-inotify.o > util-obj-$(CONFIG_LINUX) += vfio-helpers.o > util-obj-$(CONFIG_OPENGL) += drm.o > +util-obj-y += guest-random.o > > stub-obj-y += filemonitor-stub.o >
diff --git a/include/qemu/guest-random.h b/include/qemu/guest-random.h new file mode 100644 index 0000000000..09ff9c2236 --- /dev/null +++ b/include/qemu/guest-random.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#ifndef QEMU_GUEST_RANDOM_H +#define QEMU_GUEST_RANDOM_H + +/** + * qemu_guest_random_seed_main(const char *optarg, Error **errp) + * @optarg: a non-NULL pointer to a C string + * @errp: an error indicator + * + * The @optarg value is that which accompanies the -seed argument. + * This forces qemu_guest_getrandom into deterministic mode. + * + * Returns 0 on success, < 0 on failure while setting *errp. + */ +int qemu_guest_random_seed_main(const char *optarg, Error **errp); + +/** + * qemu_guest_random_seed_thread_part1(void) + * + * If qemu_getrandom is in deterministic mode, returns an + * independent seed for the new thread. Otherwise returns 0. + */ +uint64_t qemu_guest_random_seed_thread_part1(void); + +/** + * qemu_guest_random_seed_thread_part2(uint64_t seed) + * @seed: a value for the new thread. + * + * If qemu_guest_getrandom is in deterministic mode, this stores an + * independent seed for the new thread. Otherwise a no-op. + */ +void qemu_guest_random_seed_thread_part2(uint64_t seed); + +/** + * qemu_guest_getrandom(void *buf, size_t len, Error **errp) + * @buf: a buffer of bytes to be written + * @len: the number of bytes in @buf + * @errp: an error indicator + * + * Fills len bytes in buf with random data. This should only be used + * for data presented to the guest. Host-side crypto services should + * use qcrypto_random_bytes. + * + * Returns 0 on success, < 0 on failure while setting *errp. + */ +int qemu_guest_getrandom(void *buf, size_t len, Error **errp); + +/** + * qemu_guest_getrandom_nofail(void *buf, size_t len) + * @buf: a buffer of bytes to be written + * @len: the number of bytes in @buf + * + * Like qemu_guest_getrandom, but will assert for failure. + * Use this when there is no reasonable recovery. + */ +void qemu_guest_getrandom_nofail(void *buf, size_t len); + +#endif /* QEMU_GUEST_RANDOM_H */ diff --git a/util/guest-random.c b/util/guest-random.c new file mode 100644 index 0000000000..e8124a3cad --- /dev/null +++ b/util/guest-random.c @@ -0,0 +1,93 @@ +/* + * 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-common.h" +#include "qemu/cutils.h" +#include "qapi/error.h" +#include "qemu/guest-random.h" +#include "crypto/random.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, i - len); + } + return 0; +} + +int qemu_guest_getrandom(void *buf, size_t len, Error **errp) +{ + if (unlikely(deterministic)) { + /* Deterministic implementation using Glib's Mersenne Twister. */ + return glib_random_bytes(buf, len); + } else { + /* Non-deterministic implementation using crypto routines. */ + return qcrypto_random_bytes(buf, len, errp); + } +} + +void qemu_guest_getrandom_nofail(void *buf, size_t len) +{ + 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) +{ + unsigned long long seed; + if (parse_uint_full(optarg, &seed, 0)) { + error_setg(errp, "Invalid seed number: %s", optarg); + return -1; + } else { + deterministic = true; + qemu_guest_random_seed_thread_part2(seed); + return 0; + } +} diff --git a/util/Makefile.objs b/util/Makefile.objs index 835fcd69e2..4d4db653cc 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -53,5 +53,6 @@ util-obj-y += iova-tree.o util-obj-$(CONFIG_INOTIFY1) += filemonitor-inotify.o util-obj-$(CONFIG_LINUX) += vfio-helpers.o util-obj-$(CONFIG_OPENGL) += drm.o +util-obj-y += guest-random.o stub-obj-y += filemonitor-stub.o
This routine is intended to produce high-quality random numbers to the guest. Normally, such numbers are crypto quality from the host, but a command-line option can force the use of a fully deterministic sequence for use while debugging. Cc: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/qemu/guest-random.h | 68 +++++++++++++++++++++++++++ util/guest-random.c | 93 +++++++++++++++++++++++++++++++++++++ util/Makefile.objs | 1 + 3 files changed, 162 insertions(+) create mode 100644 include/qemu/guest-random.h create mode 100644 util/guest-random.c -- 2.17.2