Upload upstream chromium 94.0.4606.31
[platform/framework/web/chromium-efl.git] / base / rand_util_posix.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/rand_util.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <unistd.h>
12
13 #include "base/check.h"
14 #include "base/compiler_specific.h"
15 #include "base/files/file_util.h"
16 #include "base/no_destructor.h"
17 #include "base/posix/eintr_wrapper.h"
18 #include "build/build_config.h"
19
20 #if (defined(OS_LINUX) || defined(OS_CHROMEOS)) && !defined(OS_NACL)
21 #include "third_party/lss/linux_syscall_support.h"
22 #elif defined(OS_MAC)
23 // TODO(crbug.com/995996): Waiting for this header to appear in the iOS SDK.
24 // (See below.)
25 #include <sys/random.h>
26 #endif
27
28 namespace {
29
30 #if defined(OS_AIX)
31 // AIX has no 64-bit support for O_CLOEXEC.
32 static constexpr int kOpenFlags = O_RDONLY;
33 #else
34 static constexpr int kOpenFlags = O_RDONLY | O_CLOEXEC;
35 #endif
36
37 // We keep the file descriptor for /dev/urandom around so we don't need to
38 // reopen it (which is expensive), and since we may not even be able to reopen
39 // it if we are later put in a sandbox. This class wraps the file descriptor so
40 // we can use a static-local variable to handle opening it on the first access.
41 class URandomFd {
42  public:
43   URandomFd() : fd_(HANDLE_EINTR(open("/dev/urandom", kOpenFlags))) {
44     CHECK(fd_ >= 0) << "Cannot open /dev/urandom";
45   }
46
47   ~URandomFd() { close(fd_); }
48
49   int fd() const { return fd_; }
50
51  private:
52   const int fd_;
53 };
54
55 }  // namespace
56
57 namespace base {
58
59 // NOTE: In an ideal future, all implementations of this function will just
60 // wrap BoringSSL's `RAND_bytes`. TODO(crbug.com/995996): Figure out the
61 // build/test/performance issues with dcheng's CL
62 // (https://chromium-review.googlesource.com/c/chromium/src/+/1545096) and land
63 // it or some form of it.
64 void RandBytes(void* output, size_t output_length) {
65 #if (defined(OS_LINUX) || defined(OS_CHROMEOS)) && !defined(OS_NACL)
66   // We have to call `getrandom` via Linux Syscall Support, rather than through
67   // the libc wrapper, because we might not have an up-to-date libc (e.g. on
68   // some bots).
69   const ssize_t r = HANDLE_EINTR(sys_getrandom(output, output_length, 0));
70
71   // Return success only on total success. In case errno == ENOSYS (or any other
72   // error), we'll fall through to reading from urandom below.
73   if (output_length == static_cast<size_t>(r)) {
74     MSAN_UNPOISON(output, output_length);
75     return;
76   }
77 #elif defined(OS_MAC)
78   // TODO(crbug.com/995996): Enable this on iOS too, when sys/random.h arrives
79   // in its SDK.
80   if (__builtin_available(macOS 10.12, *)) {
81     if (getentropy(output, output_length) == 0) {
82       return;
83     }
84   }
85 #endif
86
87   // If the OS-specific mechanisms didn't work, fall through to reading from
88   // urandom.
89   //
90   // TODO(crbug.com/995996): When we no longer need to support old Linux
91   // kernels, we can get rid of this /dev/urandom branch altogether.
92   const int urandom_fd = GetUrandomFD();
93   const bool success =
94       ReadFromFD(urandom_fd, static_cast<char*>(output), output_length);
95   CHECK(success);
96 }
97
98 int GetUrandomFD() {
99   static NoDestructor<URandomFd> urandom_fd;
100   return urandom_fd->fd();
101 }
102
103 }  // namespace base