RandomNum.cpp (3999B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/RandomNum.h" 8 9 #ifdef XP_UNIX 10 # include <fcntl.h> 11 # include <unistd.h> 12 #endif 13 14 #if defined(XP_WIN) 15 16 // Microsoft doesn't "officially" support using RtlGenRandom() directly 17 // anymore, and the Windows headers assume that __stdcall is 18 // the default calling convention (which is true when Microsoft uses this 19 // function to build their own CRT libraries). 20 21 // We will explicitly declare it with the proper calling convention. 22 23 # include "minwindef.h" 24 # define RtlGenRandom SystemFunction036 25 extern "C" BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, 26 ULONG RandomBufferLength); 27 28 #endif 29 30 #if defined(ANDROID) || defined(XP_DARWIN) || defined(__DragonFly__) || \ 31 defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ 32 defined(__wasi__) 33 # define USE_ARC4RANDOM 34 #endif 35 36 #if defined(__linux__) 37 # include <linux/random.h> // For GRND_NONBLOCK. 38 # include <sys/syscall.h> // For SYS_getrandom. 39 40 // Older glibc versions don't define SYS_getrandom, so we define it here if 41 // it's not available. See bug 995069. 42 # if defined(__x86_64__) 43 # define GETRANDOM_NR 318 44 # elif defined(__i386__) 45 # define GETRANDOM_NR 355 46 # elif defined(__aarch64__) 47 # define GETRANDOM_NR 278 48 # elif defined(__arm__) 49 # define GETRANDOM_NR 384 50 # elif defined(__powerpc__) 51 # define GETRANDOM_NR 359 52 # elif defined(__s390__) 53 # define GETRANDOM_NR 349 54 # elif defined(__mips__) 55 # include <sgidefs.h> 56 # if _MIPS_SIM == _MIPS_SIM_ABI32 57 # define GETRANDOM_NR 4353 58 # elif _MIPS_SIM == _MIPS_SIM_ABI64 59 # define GETRANDOM_NR 5313 60 # elif _MIPS_SIM == _MIPS_SIM_NABI32 61 # define GETRANDOM_NR 6317 62 # endif 63 # endif 64 65 # if defined(SYS_getrandom) 66 // We have SYS_getrandom. Use it to check GETRANDOM_NR. Only do this if we set 67 // GETRANDOM_NR so tier 3 platforms with recent glibc are not forced to define 68 // it for no good reason. 69 # if defined(GETRANDOM_NR) 70 static_assert(GETRANDOM_NR == SYS_getrandom, 71 "GETRANDOM_NR should match the actual SYS_getrandom value"); 72 # endif 73 # else 74 # define SYS_getrandom GETRANDOM_NR 75 # endif 76 77 # if defined(GRND_NONBLOCK) 78 static_assert(GRND_NONBLOCK == 1, 79 "If GRND_NONBLOCK is not 1 the #define below is wrong"); 80 # else 81 # define GRND_NONBLOCK 1 82 # endif 83 84 #endif // defined(__linux__) 85 86 namespace mozilla { 87 88 MFBT_API bool GenerateRandomBytesFromOS(void* aBuffer, size_t aLength) { 89 MOZ_ASSERT(aBuffer); 90 MOZ_ASSERT(aLength > 0); 91 92 #if defined(XP_WIN) 93 return !!RtlGenRandom(aBuffer, aLength); 94 95 #elif defined(USE_ARC4RANDOM) // defined(XP_WIN) 96 97 arc4random_buf(aBuffer, aLength); 98 return true; 99 100 #elif defined(XP_UNIX) // defined(USE_ARC4RANDOM) 101 102 # if defined(__linux__) 103 104 long bytesGenerated = syscall(SYS_getrandom, aBuffer, aLength, GRND_NONBLOCK); 105 106 if (static_cast<unsigned long>(bytesGenerated) == aLength) { 107 return true; 108 } 109 110 // Fall-through to UNIX behavior if failed 111 112 # endif // defined(__linux__) 113 114 int fd = open("/dev/urandom", O_RDONLY); 115 if (fd < 0) { 116 return false; 117 } 118 119 ssize_t bytesRead = read(fd, aBuffer, aLength); 120 121 close(fd); 122 123 return (static_cast<size_t>(bytesRead) == aLength); 124 125 #else // defined(XP_UNIX) 126 # error "Platform needs to implement GenerateRandomBytesFromOS()" 127 #endif 128 } 129 130 MFBT_API Maybe<uint64_t> RandomUint64() { 131 uint64_t randomNum; 132 if (!GenerateRandomBytesFromOS(&randomNum, sizeof(randomNum))) { 133 return Nothing(); 134 } 135 136 return Some(randomNum); 137 } 138 139 MFBT_API uint64_t RandomUint64OrDie() { 140 uint64_t randomNum; 141 MOZ_RELEASE_ASSERT(GenerateRandomBytesFromOS(&randomNum, sizeof(randomNum))); 142 return randomNum; 143 } 144 145 } // namespace mozilla