Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors |
[email protected] | 05f9b68 | 2008-09-29 22:18:01 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Tom Sepez | 8726d30e | 2025-01-29 02:11:08 | [diff] [blame] | 5 | #ifdef UNSAFE_BUFFERS_BUILD |
| 6 | // TODO(crbug.com/390223051): Remove C-library calls to fix the errors. |
| 7 | #pragma allow_unsafe_libc_calls |
| 8 | #endif |
| 9 | |
[email protected] | 05f9b68 | 2008-09-29 22:18:01 | [diff] [blame] | 10 | #include "base/rand_util.h" |
| 11 | |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 12 | #include <errno.h> |
[email protected] | 05f9b68 | 2008-09-29 22:18:01 | [diff] [blame] | 13 | #include <fcntl.h> |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 14 | #include <stddef.h> |
| 15 | #include <stdint.h> |
| 16 | #include <sys/syscall.h> |
| 17 | #include <sys/utsname.h> |
| 18 | #include <unistd.h> |
[email protected] | 05f9b68 | 2008-09-29 22:18:01 | [diff] [blame] | 19 | |
Hans Wennborg | c3cffa6 | 2020-04-27 10:09:12 | [diff] [blame] | 20 | #include "base/check.h" |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 21 | #include "base/compiler_specific.h" |
Austin Sullivan | a41f7f6 | 2024-01-09 20:11:50 | [diff] [blame] | 22 | #include "base/containers/span.h" |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 23 | #include "base/feature_list.h" |
[email protected] | e3177dd5 | 2014-08-13 20:22:14 | [diff] [blame] | 24 | #include "base/files/file_util.h" |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 25 | #include "base/metrics/histogram_macros.h" |
| 26 | #include "base/no_destructor.h" |
mark | 4cec494 | 2017-02-28 23:56:00 | [diff] [blame] | 27 | #include "base/posix/eintr_wrapper.h" |
Anand Ravi | c4987db | 2025-03-10 21:32:09 | [diff] [blame] | 28 | #include "base/system/sys_info.h" |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 29 | #include "base/time/time.h" |
Chris Palmer | 254cd5f | 2020-08-12 20:37:07 | [diff] [blame] | 30 | #include "build/build_config.h" |
| 31 | |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 32 | #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && !BUILDFLAG(IS_NACL) |
| 33 | #include "third_party/lss/linux_syscall_support.h" |
| 34 | #elif BUILDFLAG(IS_MAC) |
Alison Gale | d965ba0 | 2024-04-26 21:50:54 | [diff] [blame] | 35 | // TODO(crbug.com/40641285): Waiting for this header to appear in the iOS SDK. |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 36 | // (See below.) |
| 37 | #include <sys/random.h> |
| 38 | #endif |
| 39 | |
Daniel Cheng | b6bbf5a6 | 2022-09-09 18:26:34 | [diff] [blame] | 40 | #if !BUILDFLAG(IS_NACL) |
Daniel Cheng | b6bbf5a6 | 2022-09-09 18:26:34 | [diff] [blame] | 41 | #include "third_party/boringssl/src/include/openssl/rand.h" |
| 42 | #endif |
| 43 | |
| 44 | namespace base { |
| 45 | |
[email protected] | 09e5f47a | 2009-06-26 10:00:02 | [diff] [blame] | 46 | namespace { |
| 47 | |
Xiaohan Wang | 38e4ebb | 2022-01-19 06:57:43 | [diff] [blame] | 48 | #if BUILDFLAG(IS_AIX) |
Chris Palmer | 3b3588b | 2020-08-28 17:04:21 | [diff] [blame] | 49 | // AIX has no 64-bit support for O_CLOEXEC. |
| 50 | static constexpr int kOpenFlags = O_RDONLY; |
| 51 | #else |
| 52 | static constexpr int kOpenFlags = O_RDONLY | O_CLOEXEC; |
| 53 | #endif |
| 54 | |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 55 | // We keep the file descriptor for /dev/urandom around so we don't need to |
| 56 | // reopen it (which is expensive), and since we may not even be able to reopen |
| 57 | // it if we are later put in a sandbox. This class wraps the file descriptor so |
| 58 | // we can use a static-local variable to handle opening it on the first access. |
| 59 | class URandomFd { |
| 60 | public: |
| 61 | URandomFd() : fd_(HANDLE_EINTR(open("/dev/urandom", kOpenFlags))) { |
| 62 | CHECK(fd_ >= 0) << "Cannot open /dev/urandom"; |
| 63 | } |
| 64 | |
| 65 | ~URandomFd() { close(fd_); } |
| 66 | |
| 67 | int fd() const { return fd_; } |
| 68 | |
| 69 | private: |
| 70 | const int fd_; |
| 71 | }; |
| 72 | |
| 73 | #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \ |
| 74 | BUILDFLAG(IS_ANDROID)) && \ |
| 75 | !BUILDFLAG(IS_NACL) |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 76 | |
| 77 | bool KernelSupportsGetRandom() { |
Anand Ravi | c4987db | 2025-03-10 21:32:09 | [diff] [blame] | 78 | return base::SysInfo::KernelVersionNumber::Current() >= |
| 79 | base::SysInfo::KernelVersionNumber(3, 17); |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 80 | } |
| 81 | |
| 82 | bool GetRandomSyscall(void* output, size_t output_length) { |
| 83 | // We have to call `getrandom` via Linux Syscall Support, rather than through |
| 84 | // the libc wrapper, because we might not have an up-to-date libc (e.g. on |
| 85 | // some bots). |
| 86 | const ssize_t r = |
| 87 | HANDLE_EINTR(syscall(__NR_getrandom, output, output_length, 0)); |
| 88 | |
| 89 | // Return success only on total success. In case errno == ENOSYS (or any other |
| 90 | // error), we'll fall through to reading from urandom below. |
| 91 | if (output_length == static_cast<size_t>(r)) { |
| 92 | MSAN_UNPOISON(output, output_length); |
| 93 | return true; |
| 94 | } |
| 95 | return false; |
| 96 | } |
| 97 | #endif // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || |
| 98 | // BUILDFLAG(IS_ANDROID)) && !BUILDFLAG(IS_NACL) |
| 99 | |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 100 | } // namespace |
| 101 | |
| 102 | namespace internal { |
| 103 | |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 104 | namespace { |
| 105 | |
| 106 | #if !BUILDFLAG(IS_NACL) |
| 107 | // The BoringSSl helpers are duplicated in rand_util_fuchsia.cc and |
| 108 | // rand_util_win.cc. |
| 109 | std::atomic<bool> g_use_boringssl; |
| 110 | |
| 111 | BASE_FEATURE(kUseBoringSSLForRandBytes, |
| 112 | "UseBoringSSLForRandBytes", |
| 113 | FEATURE_DISABLED_BY_DEFAULT); |
| 114 | |
| 115 | } // namespace |
| 116 | |
| 117 | void ConfigureBoringSSLBackedRandBytesFieldTrial() { |
| 118 | g_use_boringssl.store(FeatureList::IsEnabled(kUseBoringSSLForRandBytes), |
| 119 | std::memory_order_relaxed); |
| 120 | } |
| 121 | |
| 122 | bool UseBoringSSLForRandBytes() { |
| 123 | return g_use_boringssl.load(std::memory_order_relaxed); |
| 124 | } |
| 125 | #endif |
| 126 | |
| 127 | } // namespace internal |
| 128 | |
| 129 | namespace { |
| 130 | |
danakj | 95305d27 | 2024-05-09 20:38:44 | [diff] [blame] | 131 | void RandBytesInternal(span<uint8_t> output, bool avoid_allocation) { |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 132 | #if !BUILDFLAG(IS_NACL) |
| 133 | // The BoringSSL experiment takes priority over everything else. |
| 134 | if (!avoid_allocation && internal::UseBoringSSLForRandBytes()) { |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 135 | // BoringSSL's RAND_bytes always returns 1. Any error aborts the program. |
Austin Sullivan | a41f7f6 | 2024-01-09 20:11:50 | [diff] [blame] | 136 | (void)RAND_bytes(output.data(), output.size()); |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 137 | return; |
| 138 | } |
| 139 | #endif |
| 140 | #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \ |
| 141 | BUILDFLAG(IS_ANDROID)) && \ |
| 142 | !BUILDFLAG(IS_NACL) |
Morten Stenshorne | 214ec70 | 2024-11-04 22:54:08 | [diff] [blame] | 143 | // On Android it is mandatory to check that the kernel _version_ has the |
| 144 | // support for a syscall before calling. The same check is made on Linux and |
| 145 | // ChromeOS to avoid making a syscall that predictably returns ENOSYS. |
| 146 | static const bool kernel_has_support = KernelSupportsGetRandom(); |
| 147 | if (kernel_has_support && GetRandomSyscall(output.data(), output.size())) { |
| 148 | return; |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 149 | } |
| 150 | #elif BUILDFLAG(IS_MAC) |
Alison Gale | d965ba0 | 2024-04-26 21:50:54 | [diff] [blame] | 151 | // TODO(crbug.com/40641285): Enable this on iOS too, when sys/random.h arrives |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 152 | // in its SDK. |
Austin Sullivan | a41f7f6 | 2024-01-09 20:11:50 | [diff] [blame] | 153 | if (getentropy(output.data(), output.size()) == 0) { |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 154 | return; |
| 155 | } |
| 156 | #endif |
| 157 | |
| 158 | // If the OS-specific mechanisms didn't work, fall through to reading from |
| 159 | // urandom. |
| 160 | // |
Alison Gale | d965ba0 | 2024-04-26 21:50:54 | [diff] [blame] | 161 | // TODO(crbug.com/40641285): When we no longer need to support old Linux |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 162 | // kernels, we can get rid of this /dev/urandom branch altogether. |
| 163 | const int urandom_fd = GetUrandomFD(); |
Austin Sullivan | a41f7f6 | 2024-01-09 20:11:50 | [diff] [blame] | 164 | const bool success = ReadFromFD(urandom_fd, as_writable_chars(output)); |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 165 | CHECK(success); |
[email protected] | c910c5a | 2014-01-23 02:14:28 | [diff] [blame] | 166 | } |
| 167 | |
Egor Pasko | 1c7e624 | 2022-09-20 12:45:39 | [diff] [blame] | 168 | } // namespace |
| 169 | |
| 170 | namespace internal { |
| 171 | |
| 172 | double RandDoubleAvoidAllocation() { |
| 173 | uint64_t number; |
danakj | 95305d27 | 2024-05-09 20:38:44 | [diff] [blame] | 174 | RandBytesInternal(byte_span_from_ref(number), /*avoid_allocation=*/true); |
Egor Pasko | 1c7e624 | 2022-09-20 12:45:39 | [diff] [blame] | 175 | // This transformation is explained in rand_util.cc. |
| 176 | return (number >> 11) * 0x1.0p-53; |
| 177 | } |
| 178 | |
| 179 | } // namespace internal |
| 180 | |
Austin Sullivan | a41f7f6 | 2024-01-09 20:11:50 | [diff] [blame] | 181 | void RandBytes(span<uint8_t> output) { |
danakj | 95305d27 | 2024-05-09 20:38:44 | [diff] [blame] | 182 | RandBytesInternal(output, /*avoid_allocation=*/false); |
Egor Pasko | 1c7e624 | 2022-09-20 12:45:39 | [diff] [blame] | 183 | } |
| 184 | |
Lei Zhang | e3e126d78 | 2020-01-07 21:36:00 | [diff] [blame] | 185 | int GetUrandomFD() { |
Mark Mentovai | 5d6e763 | 2023-08-11 17:21:43 | [diff] [blame] | 186 | static NoDestructor<URandomFd> urandom_fd; |
| 187 | return urandom_fd->fd(); |
[email protected] | 1d87fad | 2010-03-04 20:18:55 | [diff] [blame] | 188 | } |
[email protected] | ead8c1f | 2012-05-30 14:26:13 | [diff] [blame] | 189 | |
| 190 | } // namespace base |