no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / mfbt / RandomNum.cpp
blob96de5d40553e6b6708a4255ca5bcfdac177437e1
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/. */
7 #include "mozilla/RandomNum.h"
9 #include <fcntl.h>
10 #ifdef XP_UNIX
11 # include <unistd.h>
12 #endif
14 #if defined(XP_WIN)
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).
21 // We will explicitly declare it with the proper calling convention.
23 # include "minwindef.h"
24 # define RtlGenRandom SystemFunction036
25 extern "C" BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer,
26 ULONG RandomBufferLength);
28 #endif
30 #if defined(ANDROID) || defined(XP_DARWIN) || defined(__DragonFly__) || \
31 defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
32 defined(__wasi__)
33 # include <stdlib.h>
34 # define USE_ARC4RANDOM
35 #endif
37 #if defined(__linux__)
38 # include <linux/random.h> // For GRND_NONBLOCK.
39 # include <sys/syscall.h> // For SYS_getrandom.
41 // Older glibc versions don't define SYS_getrandom, so we define it here if
42 // it's not available. See bug 995069.
43 # if defined(__x86_64__)
44 # define GETRANDOM_NR 318
45 # elif defined(__i386__)
46 # define GETRANDOM_NR 355
47 # elif defined(__aarch64__)
48 # define GETRANDOM_NR 278
49 # elif defined(__arm__)
50 # define GETRANDOM_NR 384
51 # elif defined(__powerpc__)
52 # define GETRANDOM_NR 359
53 # elif defined(__s390__)
54 # define GETRANDOM_NR 349
55 # elif defined(__mips__)
56 # include <sgidefs.h>
57 # if _MIPS_SIM == _MIPS_SIM_ABI32
58 # define GETRANDOM_NR 4353
59 # elif _MIPS_SIM == _MIPS_SIM_ABI64
60 # define GETRANDOM_NR 5313
61 # elif _MIPS_SIM == _MIPS_SIM_NABI32
62 # define GETRANDOM_NR 6317
63 # endif
64 # endif
66 # if defined(SYS_getrandom)
67 // We have SYS_getrandom. Use it to check GETRANDOM_NR. Only do this if we set
68 // GETRANDOM_NR so tier 3 platforms with recent glibc are not forced to define
69 // it for no good reason.
70 # if defined(GETRANDOM_NR)
71 static_assert(GETRANDOM_NR == SYS_getrandom,
72 "GETRANDOM_NR should match the actual SYS_getrandom value");
73 # endif
74 # else
75 # define SYS_getrandom GETRANDOM_NR
76 # endif
78 # if defined(GRND_NONBLOCK)
79 static_assert(GRND_NONBLOCK == 1,
80 "If GRND_NONBLOCK is not 1 the #define below is wrong");
81 # else
82 # define GRND_NONBLOCK 1
83 # endif
85 #endif // defined(__linux__)
87 namespace mozilla {
89 MFBT_API bool GenerateRandomBytesFromOS(void* aBuffer, size_t aLength) {
90 MOZ_ASSERT(aBuffer);
91 MOZ_ASSERT(aLength > 0);
93 #if defined(XP_WIN)
94 return !!RtlGenRandom(aBuffer, aLength);
96 #elif defined(USE_ARC4RANDOM) // defined(XP_WIN)
98 arc4random_buf(aBuffer, aLength);
99 return true;
101 #elif defined(XP_UNIX) // defined(USE_ARC4RANDOM)
103 # if defined(__linux__)
105 long bytesGenerated = syscall(SYS_getrandom, aBuffer, aLength, GRND_NONBLOCK);
107 if (static_cast<unsigned long>(bytesGenerated) == aLength) {
108 return true;
111 // Fall-through to UNIX behavior if failed
113 # endif // defined(__linux__)
115 int fd = open("/dev/urandom", O_RDONLY);
116 if (fd < 0) {
117 return false;
120 ssize_t bytesRead = read(fd, aBuffer, aLength);
122 close(fd);
124 return (static_cast<size_t>(bytesRead) == aLength);
126 #else // defined(XP_UNIX)
127 # error "Platform needs to implement GenerateRandomBytesFromOS()"
128 #endif
131 MFBT_API Maybe<uint64_t> RandomUint64() {
132 uint64_t randomNum;
133 if (!GenerateRandomBytesFromOS(&randomNum, sizeof(randomNum))) {
134 return Nothing();
137 return Some(randomNum);
140 MFBT_API uint64_t RandomUint64OrDie() {
141 uint64_t randomNum;
142 MOZ_RELEASE_ASSERT(GenerateRandomBytesFromOS(&randomNum, sizeof(randomNum)));
143 return randomNum;
146 } // namespace mozilla