From e95ef67b35726e80ebeabeb3633268cb82176cdc Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 25 Jan 2012 15:17:46 +0000 Subject: [PATCH] Introduce new API for generating random numbers The old virRandom() API was not generating good random numbers. Replace it with a new API virRandomBits which instead of being told the upper limit, gets told the number of bits of randomness required. * src/util/virrandom.c, src/util/virrandom.h: Add virRandomBits, and move virRandomInitialize * src/util/util.h, src/util/util.c: Delete virRandom and virRandomInitialize * src/libvirt.c, src/security/security_selinux.c, src/test/test_driver.c, src/util/iohelper.c: Update for changes from virRandom to virRandomBits * src/storage/storage_backend_iscsi.c: Remove bogus call to virRandomInitialize & convert to virRandomBits --- src/Makefile.am | 1 + src/libvirt.c | 2 +- src/libvirt_private.syms | 7 ++- src/security/security_selinux.c | 5 +- src/storage/storage_backend_iscsi.c | 12 ++--- src/test/test_driver.c | 3 +- src/util/iohelper.c | 1 + src/util/util.c | 37 ++----------- src/util/util.h | 3 -- src/util/uuid.c | 3 +- src/util/virrandom.c | 81 +++++++++++++++++++++++++++++ src/util/virrandom.h | 30 +++++++++++ tests/testutils.c | 3 +- 13 files changed, 135 insertions(+), 53 deletions(-) create mode 100644 src/util/virrandom.c create mode 100644 src/util/virrandom.h diff --git a/src/Makefile.am b/src/Makefile.am index a44446f4d4..4629700a0d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -99,6 +99,7 @@ UTIL_SOURCES = \ util/virnetdevtap.h util/virnetdevtap.c \ util/virnetdevveth.h util/virnetdevveth.c \ util/virnetdevvportprofile.h util/virnetdevvportprofile.c \ + util/virrandom.h util/virrandom.c \ util/virsocketaddr.h util/virsocketaddr.c \ util/virtime.h util/virtime.c diff --git a/src/libvirt.c b/src/libvirt.c index 8be4e13cec..e9d638bc47 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -36,7 +36,6 @@ #include "driver.h" #include "uuid.h" -#include "util.h" #include "memory.h" #include "configmake.h" #include "intprops.h" @@ -44,6 +43,7 @@ #include "rpc/virnettlscontext.h" #include "command.h" #include "virnodesuspend.h" +#include "virrandom.h" #ifndef WITH_DRIVER_MODULES # ifdef WITH_TEST diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 924ec16c78..915a43f12e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1126,8 +1126,6 @@ virParseMacAddr; virParseNumber; virParseVersionString; virPipeReadUntilEOF; -virRandom; -virRandomInitialize; virSetBlocking; virSetCloseExec; virSetInherit; @@ -1369,6 +1367,11 @@ virPidFileDelete; virPidFileDeletePath; +# virrandom.h +virRandomBits; +virRandomInitialize; + + # virsocketaddr.h virSocketAddrBroadcast; virSocketAddrBroadcastByPrefix; diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index c2dcecabe1..cb41a17c52 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -32,6 +32,7 @@ #include "hostusb.h" #include "storage_file.h" #include "virfile.h" +#include "virrandom.h" #define VIR_FROM_THIS VIR_FROM_SECURITY @@ -216,8 +217,8 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, } } else { do { - c1 = virRandom(1024); - c2 = virRandom(1024); + c1 = virRandomBits(10); + c2 = virRandomBits(10); if ( c1 == c2 ) { if (virAsprintf(&mcs, "s0:c%d", c1) < 0) { diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c index 354f99be9a..6ebc6e1631 100644 --- a/src/storage/storage_backend_iscsi.c +++ b/src/storage/storage_backend_iscsi.c @@ -42,6 +42,7 @@ #include "logging.h" #include "virfile.h" #include "command.h" +#include "virrandom.h" #define VIR_FROM_THIS VIR_FROM_STORAGE @@ -283,15 +284,8 @@ virStorageBackendCreateIfaceIQN(const char *initiatoriqn, initiatoriqn, NULL }; - if (virRandomInitialize(time(NULL) ^ getpid()) == -1) { - virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Failed to initialize random generator " - "when creating iscsi interface")); - goto out; - } - - snprintf(temp_ifacename, sizeof(temp_ifacename), "libvirt-iface-%08x", - virRandom(1024 * 1024 * 1024)); + snprintf(temp_ifacename, sizeof(temp_ifacename), "libvirt-iface-%08llx", + (unsigned long long)virRandomBits(30)); VIR_DEBUG("Attempting to create interface '%s' with IQN '%s'", &temp_ifacename[0], initiatoriqn); diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 55b889b148..bf6b14835b 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -51,6 +51,7 @@ #include "logging.h" #include "virfile.h" #include "virtypedparam.h" +#include "virrandom.h" #define VIR_FROM_THIS VIR_FROM_TEST @@ -5316,7 +5317,7 @@ testNodeDeviceCreateXML(virConnectPtr conn, if (caps->type != VIR_NODE_DEV_CAP_SCSI_HOST) continue; - caps->data.scsi_host.host = virRandom(1024); + caps->data.scsi_host.host = virRandomBits(10); caps = caps->next; } diff --git a/src/util/iohelper.c b/src/util/iohelper.c index 93154f8945..079419312e 100644 --- a/src/util/iohelper.c +++ b/src/util/iohelper.c @@ -39,6 +39,7 @@ #include "memory.h" #include "virterror_internal.h" #include "configmake.h" +#include "virrandom.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/util/util.c b/src/util/util.c index 33bcf29317..f1c3346765 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -77,6 +77,7 @@ #include "command.h" #include "nonblocking.h" #include "passfd.h" +#include "virrandom.h" #ifndef NSIG # define NSIG 32 @@ -1853,9 +1854,9 @@ void virGenerateMacAddr(const unsigned char *prefix, addr[0] = prefix[0]; addr[1] = prefix[1]; addr[2] = prefix[2]; - addr[3] = virRandom(256); - addr[4] = virRandom(256); - addr[5] = virRandom(256); + addr[3] = virRandomBits(8); + addr[4] = virRandomBits(8); + addr[5] = virRandomBits(8); } @@ -2097,36 +2098,6 @@ int virKillProcess(pid_t pid, int sig) } -static char randomState[128]; -static struct random_data randomData; -static virMutex randomLock; - -int virRandomInitialize(unsigned int seed) -{ - if (virMutexInit(&randomLock) < 0) - return -1; - - if (initstate_r(seed, - randomState, - sizeof(randomState), - &randomData) < 0) - return -1; - - return 0; -} - -int virRandom(int max) -{ - int32_t ret; - - virMutexLock(&randomLock); - random_r(&randomData, &ret); - virMutexUnlock(&randomLock); - - return (int) ((double)max * ((double)ret / (double)RAND_MAX)); -} - - #ifdef HAVE_GETPWUID_R enum { VIR_USER_ENT_DIRECTORY, diff --git a/src/util/util.h b/src/util/util.h index 94d92828f5..91cae47ac1 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -242,9 +242,6 @@ int virGetUserID(const char *name, int virGetGroupID(const char *name, gid_t *gid) ATTRIBUTE_RETURN_CHECK; -int virRandomInitialize(unsigned int seed) ATTRIBUTE_RETURN_CHECK; -int virRandom(int max); - char *virFileFindMountPoint(const char *type); void virFileWaitForDevices(void); diff --git a/src/util/uuid.c b/src/util/uuid.c index 15ba5af181..23822ec8f6 100644 --- a/src/util/uuid.c +++ b/src/util/uuid.c @@ -40,6 +40,7 @@ #include "logging.h" #include "memory.h" #include "virfile.h" +#include "virrandom.h" #ifndef ENODATA # define ENODATA EIO @@ -80,7 +81,7 @@ virUUIDGeneratePseudoRandomBytes(unsigned char *buf, int buflen) { while (buflen > 0) { - *buf++ = virRandom(256); + *buf++ = virRandomBits(8); buflen--; } diff --git a/src/util/virrandom.c b/src/util/virrandom.c new file mode 100644 index 0000000000..0af94d5da8 --- /dev/null +++ b/src/util/virrandom.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: + * Daniel P. Berrange + */ + +#include + +#include + +#include "virrandom.h" +#include "threads.h" +#include "count-one-bits.h" + +static char randomState[128]; +static struct random_data randomData; +static virMutex randomLock; + + +int virRandomInitialize(uint32_t seed) +{ + if (virMutexInit(&randomLock) < 0) + return -1; + + if (initstate_r(seed, + randomState, + sizeof(randomState), + &randomData) < 0) + return -1; + + return 0; +} + +/* + * virRandomBits: + * @nbits: Number of bits of randommess required + * + * Generate an evenly distributed random number between [0,2^nbits), where + * @nbits must be in the range (0,64]. + * + * Return: a random number with @nbits entropy + */ +uint64_t virRandomBits(int nbits) +{ + int bits_per_iter = count_one_bits(RAND_MAX); + uint64_t ret = 0; + int32_t bits; + + /* This algorithm requires that RAND_MAX == 2^n-1 for some n; + gnulib's random_r meets this property. */ + verify(((RAND_MAX + 1U) & RAND_MAX) == 0); + + virMutexLock(&randomLock); + + while (nbits > bits_per_iter) { + random_r(&randomData, &bits); + ret = (ret << bits_per_iter) | (bits & RAND_MAX); + nbits -= bits_per_iter; + } + + random_r(&randomData, &bits); + ret = (ret << nbits) | (bits & ((1 << nbits) - 1)); + + virMutexUnlock(&randomLock); + return ret; +} diff --git a/src/util/virrandom.h b/src/util/virrandom.h new file mode 100644 index 0000000000..eede3731c2 --- /dev/null +++ b/src/util/virrandom.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: + * Daniel P. Berrange + */ + +#ifndef __VIR_RANDOM_H__ +# define __VIR_RANDOM_H__ + +# include "internal.h" + +int virRandomInitialize(uint32_t seed) ATTRIBUTE_RETURN_CHECK; +uint64_t virRandomBits(int nbits); + +#endif /* __VIR_RANDOM_H__ */ diff --git a/tests/testutils.c b/tests/testutils.c index acdfdc1b40..fccea17cf2 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -1,7 +1,7 @@ /* * testutils.c: basic test utils * - * Copyright (C) 2005-2011 Red Hat, Inc. + * Copyright (C) 2005-2012 Red Hat, Inc. * * See COPYING.LIB for the License of this software * @@ -34,6 +34,7 @@ #include "buf.h" #include "logging.h" #include "command.h" +#include "virrandom.h" #if TEST_OOM_TRACE # include