tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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