xref: /aosp_15_r20/external/cronet/base/rand_util_posix.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <errno.h>
8*6777b538SAndroid Build Coastguard Worker #include <fcntl.h>
9*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
10*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
11*6777b538SAndroid Build Coastguard Worker #include <sys/syscall.h>
12*6777b538SAndroid Build Coastguard Worker #include <sys/utsname.h>
13*6777b538SAndroid Build Coastguard Worker #include <unistd.h>
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/no_destructor.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/posix/eintr_wrapper.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
24*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && !BUILDFLAG(IS_NACL)
27*6777b538SAndroid Build Coastguard Worker #include "third_party/lss/linux_syscall_support.h"
28*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_MAC)
29*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/995996): Waiting for this header to appear in the iOS SDK.
30*6777b538SAndroid Build Coastguard Worker // (See below.)
31*6777b538SAndroid Build Coastguard Worker #include <sys/random.h>
32*6777b538SAndroid Build Coastguard Worker #endif
33*6777b538SAndroid Build Coastguard Worker 
34*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_NACL)
35*6777b538SAndroid Build Coastguard Worker #include "third_party/boringssl/src/include/openssl/crypto.h"
36*6777b538SAndroid Build Coastguard Worker #include "third_party/boringssl/src/include/openssl/rand.h"
37*6777b538SAndroid Build Coastguard Worker #endif
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker namespace base {
40*6777b538SAndroid Build Coastguard Worker 
41*6777b538SAndroid Build Coastguard Worker namespace {
42*6777b538SAndroid Build Coastguard Worker 
43*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_AIX)
44*6777b538SAndroid Build Coastguard Worker // AIX has no 64-bit support for O_CLOEXEC.
45*6777b538SAndroid Build Coastguard Worker static constexpr int kOpenFlags = O_RDONLY;
46*6777b538SAndroid Build Coastguard Worker #else
47*6777b538SAndroid Build Coastguard Worker static constexpr int kOpenFlags = O_RDONLY | O_CLOEXEC;
48*6777b538SAndroid Build Coastguard Worker #endif
49*6777b538SAndroid Build Coastguard Worker 
50*6777b538SAndroid Build Coastguard Worker // We keep the file descriptor for /dev/urandom around so we don't need to
51*6777b538SAndroid Build Coastguard Worker // reopen it (which is expensive), and since we may not even be able to reopen
52*6777b538SAndroid Build Coastguard Worker // it if we are later put in a sandbox. This class wraps the file descriptor so
53*6777b538SAndroid Build Coastguard Worker // we can use a static-local variable to handle opening it on the first access.
54*6777b538SAndroid Build Coastguard Worker class URandomFd {
55*6777b538SAndroid Build Coastguard Worker  public:
URandomFd()56*6777b538SAndroid Build Coastguard Worker   URandomFd() : fd_(HANDLE_EINTR(open("/dev/urandom", kOpenFlags))) {
57*6777b538SAndroid Build Coastguard Worker     CHECK(fd_ >= 0) << "Cannot open /dev/urandom";
58*6777b538SAndroid Build Coastguard Worker   }
59*6777b538SAndroid Build Coastguard Worker 
~URandomFd()60*6777b538SAndroid Build Coastguard Worker   ~URandomFd() { close(fd_); }
61*6777b538SAndroid Build Coastguard Worker 
fd() const62*6777b538SAndroid Build Coastguard Worker   int fd() const { return fd_; }
63*6777b538SAndroid Build Coastguard Worker 
64*6777b538SAndroid Build Coastguard Worker  private:
65*6777b538SAndroid Build Coastguard Worker   const int fd_;
66*6777b538SAndroid Build Coastguard Worker };
67*6777b538SAndroid Build Coastguard Worker 
68*6777b538SAndroid Build Coastguard Worker #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
69*6777b538SAndroid Build Coastguard Worker      BUILDFLAG(IS_ANDROID)) &&                        \
70*6777b538SAndroid Build Coastguard Worker     !BUILDFLAG(IS_NACL)
71*6777b538SAndroid Build Coastguard Worker // TODO(pasko): Unify reading kernel version numbers in:
72*6777b538SAndroid Build Coastguard Worker // mojo/core/channel_linux.cc
73*6777b538SAndroid Build Coastguard Worker // chrome/browser/android/seccomp_support_detector.cc
KernelVersionNumbers(int32_t * major_version,int32_t * minor_version,int32_t * bugfix_version)74*6777b538SAndroid Build Coastguard Worker void KernelVersionNumbers(int32_t* major_version,
75*6777b538SAndroid Build Coastguard Worker                           int32_t* minor_version,
76*6777b538SAndroid Build Coastguard Worker                           int32_t* bugfix_version) {
77*6777b538SAndroid Build Coastguard Worker   struct utsname info;
78*6777b538SAndroid Build Coastguard Worker   if (uname(&info) < 0) {
79*6777b538SAndroid Build Coastguard Worker     NOTREACHED();
80*6777b538SAndroid Build Coastguard Worker     *major_version = 0;
81*6777b538SAndroid Build Coastguard Worker     *minor_version = 0;
82*6777b538SAndroid Build Coastguard Worker     *bugfix_version = 0;
83*6777b538SAndroid Build Coastguard Worker     return;
84*6777b538SAndroid Build Coastguard Worker   }
85*6777b538SAndroid Build Coastguard Worker   int num_read = sscanf(info.release, "%d.%d.%d", major_version, minor_version,
86*6777b538SAndroid Build Coastguard Worker                         bugfix_version);
87*6777b538SAndroid Build Coastguard Worker   if (num_read < 1)
88*6777b538SAndroid Build Coastguard Worker     *major_version = 0;
89*6777b538SAndroid Build Coastguard Worker   if (num_read < 2)
90*6777b538SAndroid Build Coastguard Worker     *minor_version = 0;
91*6777b538SAndroid Build Coastguard Worker   if (num_read < 3)
92*6777b538SAndroid Build Coastguard Worker     *bugfix_version = 0;
93*6777b538SAndroid Build Coastguard Worker }
94*6777b538SAndroid Build Coastguard Worker 
KernelSupportsGetRandom()95*6777b538SAndroid Build Coastguard Worker bool KernelSupportsGetRandom() {
96*6777b538SAndroid Build Coastguard Worker   int32_t major = 0;
97*6777b538SAndroid Build Coastguard Worker   int32_t minor = 0;
98*6777b538SAndroid Build Coastguard Worker   int32_t bugfix = 0;
99*6777b538SAndroid Build Coastguard Worker   KernelVersionNumbers(&major, &minor, &bugfix);
100*6777b538SAndroid Build Coastguard Worker   if (major > 3 || (major == 3 && minor >= 17))
101*6777b538SAndroid Build Coastguard Worker     return true;
102*6777b538SAndroid Build Coastguard Worker   return false;
103*6777b538SAndroid Build Coastguard Worker }
104*6777b538SAndroid Build Coastguard Worker 
GetRandomSyscall(void * output,size_t output_length)105*6777b538SAndroid Build Coastguard Worker bool GetRandomSyscall(void* output, size_t output_length) {
106*6777b538SAndroid Build Coastguard Worker   // We have to call `getrandom` via Linux Syscall Support, rather than through
107*6777b538SAndroid Build Coastguard Worker   // the libc wrapper, because we might not have an up-to-date libc (e.g. on
108*6777b538SAndroid Build Coastguard Worker   // some bots).
109*6777b538SAndroid Build Coastguard Worker   const ssize_t r =
110*6777b538SAndroid Build Coastguard Worker       HANDLE_EINTR(syscall(__NR_getrandom, output, output_length, 0));
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker   // Return success only on total success. In case errno == ENOSYS (or any other
113*6777b538SAndroid Build Coastguard Worker   // error), we'll fall through to reading from urandom below.
114*6777b538SAndroid Build Coastguard Worker   if (output_length == static_cast<size_t>(r)) {
115*6777b538SAndroid Build Coastguard Worker     MSAN_UNPOISON(output, output_length);
116*6777b538SAndroid Build Coastguard Worker     return true;
117*6777b538SAndroid Build Coastguard Worker   }
118*6777b538SAndroid Build Coastguard Worker   return false;
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker #endif  // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
121*6777b538SAndroid Build Coastguard Worker         // BUILDFLAG(IS_ANDROID)) && !BUILDFLAG(IS_NACL)
122*6777b538SAndroid Build Coastguard Worker 
123*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
124*6777b538SAndroid Build Coastguard Worker std::atomic<bool> g_use_getrandom;
125*6777b538SAndroid Build Coastguard Worker 
126*6777b538SAndroid Build Coastguard Worker // Note: the BoringSSL feature takes precedence over the getrandom() trial if
127*6777b538SAndroid Build Coastguard Worker // both are enabled.
128*6777b538SAndroid Build Coastguard Worker BASE_FEATURE(kUseGetrandomForRandBytes,
129*6777b538SAndroid Build Coastguard Worker              "UseGetrandomForRandBytes",
130*6777b538SAndroid Build Coastguard Worker              FEATURE_ENABLED_BY_DEFAULT);
131*6777b538SAndroid Build Coastguard Worker 
UseGetrandom()132*6777b538SAndroid Build Coastguard Worker bool UseGetrandom() {
133*6777b538SAndroid Build Coastguard Worker   return g_use_getrandom.load(std::memory_order_relaxed);
134*6777b538SAndroid Build Coastguard Worker }
135*6777b538SAndroid Build Coastguard Worker #elif (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && !BUILDFLAG(IS_NACL)
UseGetrandom()136*6777b538SAndroid Build Coastguard Worker bool UseGetrandom() {
137*6777b538SAndroid Build Coastguard Worker   return true;
138*6777b538SAndroid Build Coastguard Worker }
139*6777b538SAndroid Build Coastguard Worker #endif
140*6777b538SAndroid Build Coastguard Worker 
141*6777b538SAndroid Build Coastguard Worker }  // namespace
142*6777b538SAndroid Build Coastguard Worker 
143*6777b538SAndroid Build Coastguard Worker namespace internal {
144*6777b538SAndroid Build Coastguard Worker 
145*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
ConfigureRandBytesFieldTrial()146*6777b538SAndroid Build Coastguard Worker void ConfigureRandBytesFieldTrial() {
147*6777b538SAndroid Build Coastguard Worker   g_use_getrandom.store(FeatureList::IsEnabled(kUseGetrandomForRandBytes),
148*6777b538SAndroid Build Coastguard Worker                         std::memory_order_relaxed);
149*6777b538SAndroid Build Coastguard Worker }
150*6777b538SAndroid Build Coastguard Worker #endif
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker namespace {
153*6777b538SAndroid Build Coastguard Worker 
154*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_NACL)
155*6777b538SAndroid Build Coastguard Worker // The BoringSSl helpers are duplicated in rand_util_fuchsia.cc and
156*6777b538SAndroid Build Coastguard Worker // rand_util_win.cc.
157*6777b538SAndroid Build Coastguard Worker std::atomic<bool> g_use_boringssl;
158*6777b538SAndroid Build Coastguard Worker 
159*6777b538SAndroid Build Coastguard Worker BASE_FEATURE(kUseBoringSSLForRandBytes,
160*6777b538SAndroid Build Coastguard Worker              "UseBoringSSLForRandBytes",
161*6777b538SAndroid Build Coastguard Worker              FEATURE_DISABLED_BY_DEFAULT);
162*6777b538SAndroid Build Coastguard Worker 
163*6777b538SAndroid Build Coastguard Worker }  // namespace
164*6777b538SAndroid Build Coastguard Worker 
ConfigureBoringSSLBackedRandBytesFieldTrial()165*6777b538SAndroid Build Coastguard Worker void ConfigureBoringSSLBackedRandBytesFieldTrial() {
166*6777b538SAndroid Build Coastguard Worker   g_use_boringssl.store(FeatureList::IsEnabled(kUseBoringSSLForRandBytes),
167*6777b538SAndroid Build Coastguard Worker                         std::memory_order_relaxed);
168*6777b538SAndroid Build Coastguard Worker }
169*6777b538SAndroid Build Coastguard Worker 
UseBoringSSLForRandBytes()170*6777b538SAndroid Build Coastguard Worker bool UseBoringSSLForRandBytes() {
171*6777b538SAndroid Build Coastguard Worker   return g_use_boringssl.load(std::memory_order_relaxed);
172*6777b538SAndroid Build Coastguard Worker }
173*6777b538SAndroid Build Coastguard Worker #endif
174*6777b538SAndroid Build Coastguard Worker 
175*6777b538SAndroid Build Coastguard Worker }  // namespace internal
176*6777b538SAndroid Build Coastguard Worker 
177*6777b538SAndroid Build Coastguard Worker namespace {
178*6777b538SAndroid Build Coastguard Worker 
RandBytes(span<uint8_t> output,bool avoid_allocation)179*6777b538SAndroid Build Coastguard Worker void RandBytes(span<uint8_t> output, bool avoid_allocation) {
180*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_NACL)
181*6777b538SAndroid Build Coastguard Worker   // The BoringSSL experiment takes priority over everything else.
182*6777b538SAndroid Build Coastguard Worker   if (!avoid_allocation && internal::UseBoringSSLForRandBytes()) {
183*6777b538SAndroid Build Coastguard Worker     // Ensure BoringSSL is initialized so it can use things like RDRAND.
184*6777b538SAndroid Build Coastguard Worker     CRYPTO_library_init();
185*6777b538SAndroid Build Coastguard Worker     // BoringSSL's RAND_bytes always returns 1. Any error aborts the program.
186*6777b538SAndroid Build Coastguard Worker     (void)RAND_bytes(output.data(), output.size());
187*6777b538SAndroid Build Coastguard Worker     return;
188*6777b538SAndroid Build Coastguard Worker   }
189*6777b538SAndroid Build Coastguard Worker #endif
190*6777b538SAndroid Build Coastguard Worker #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
191*6777b538SAndroid Build Coastguard Worker      BUILDFLAG(IS_ANDROID)) &&                        \
192*6777b538SAndroid Build Coastguard Worker     !BUILDFLAG(IS_NACL)
193*6777b538SAndroid Build Coastguard Worker   if (avoid_allocation || UseGetrandom()) {
194*6777b538SAndroid Build Coastguard Worker     // On Android it is mandatory to check that the kernel _version_ has the
195*6777b538SAndroid Build Coastguard Worker     // support for a syscall before calling. The same check is made on Linux and
196*6777b538SAndroid Build Coastguard Worker     // ChromeOS to avoid making a syscall that predictably returns ENOSYS.
197*6777b538SAndroid Build Coastguard Worker     static const bool kernel_has_support = KernelSupportsGetRandom();
198*6777b538SAndroid Build Coastguard Worker     if (kernel_has_support && GetRandomSyscall(output.data(), output.size())) {
199*6777b538SAndroid Build Coastguard Worker       return;
200*6777b538SAndroid Build Coastguard Worker     }
201*6777b538SAndroid Build Coastguard Worker   }
202*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_MAC)
203*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/995996): Enable this on iOS too, when sys/random.h arrives
204*6777b538SAndroid Build Coastguard Worker   // in its SDK.
205*6777b538SAndroid Build Coastguard Worker   if (getentropy(output.data(), output.size()) == 0) {
206*6777b538SAndroid Build Coastguard Worker     return;
207*6777b538SAndroid Build Coastguard Worker   }
208*6777b538SAndroid Build Coastguard Worker #endif
209*6777b538SAndroid Build Coastguard Worker 
210*6777b538SAndroid Build Coastguard Worker   // If the OS-specific mechanisms didn't work, fall through to reading from
211*6777b538SAndroid Build Coastguard Worker   // urandom.
212*6777b538SAndroid Build Coastguard Worker   //
213*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/995996): When we no longer need to support old Linux
214*6777b538SAndroid Build Coastguard Worker   // kernels, we can get rid of this /dev/urandom branch altogether.
215*6777b538SAndroid Build Coastguard Worker   const int urandom_fd = GetUrandomFD();
216*6777b538SAndroid Build Coastguard Worker   const bool success = ReadFromFD(urandom_fd, as_writable_chars(output));
217*6777b538SAndroid Build Coastguard Worker   CHECK(success);
218*6777b538SAndroid Build Coastguard Worker }
219*6777b538SAndroid Build Coastguard Worker 
220*6777b538SAndroid Build Coastguard Worker }  // namespace
221*6777b538SAndroid Build Coastguard Worker 
222*6777b538SAndroid Build Coastguard Worker namespace internal {
223*6777b538SAndroid Build Coastguard Worker 
RandDoubleAvoidAllocation()224*6777b538SAndroid Build Coastguard Worker double RandDoubleAvoidAllocation() {
225*6777b538SAndroid Build Coastguard Worker   uint64_t number;
226*6777b538SAndroid Build Coastguard Worker   RandBytes(as_writable_bytes(make_span(&number, 1u)),
227*6777b538SAndroid Build Coastguard Worker             /*avoid_allocation=*/true);
228*6777b538SAndroid Build Coastguard Worker   // This transformation is explained in rand_util.cc.
229*6777b538SAndroid Build Coastguard Worker   return (number >> 11) * 0x1.0p-53;
230*6777b538SAndroid Build Coastguard Worker }
231*6777b538SAndroid Build Coastguard Worker 
232*6777b538SAndroid Build Coastguard Worker }  // namespace internal
233*6777b538SAndroid Build Coastguard Worker 
RandBytes(span<uint8_t> output)234*6777b538SAndroid Build Coastguard Worker void RandBytes(span<uint8_t> output) {
235*6777b538SAndroid Build Coastguard Worker   RandBytes(output, /*avoid_allocation=*/false);
236*6777b538SAndroid Build Coastguard Worker }
237*6777b538SAndroid Build Coastguard Worker 
RandBytes(void * output,size_t output_length)238*6777b538SAndroid Build Coastguard Worker void RandBytes(void* output, size_t output_length) {
239*6777b538SAndroid Build Coastguard Worker   RandBytes(make_span(static_cast<uint8_t*>(output), output_length));
240*6777b538SAndroid Build Coastguard Worker }
241*6777b538SAndroid Build Coastguard Worker 
GetUrandomFD()242*6777b538SAndroid Build Coastguard Worker int GetUrandomFD() {
243*6777b538SAndroid Build Coastguard Worker   static NoDestructor<URandomFd> urandom_fd;
244*6777b538SAndroid Build Coastguard Worker   return urandom_fd->fd();
245*6777b538SAndroid Build Coastguard Worker }
246*6777b538SAndroid Build Coastguard Worker 
247*6777b538SAndroid Build Coastguard Worker }  // namespace base
248