Coverage Report

Created: 2025-12-14 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/random.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*
15
 * Portions of isc_random_uniform():
16
 *
17
 * Copyright (c) 1996, David Mazieres <dm@uun.org>
18
 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
19
 *
20
 * Permission to use, copy, modify, and distribute this software for any
21
 * purpose with or without fee is hereby granted, provided that the above
22
 * copyright notice and this permission notice appear in all copies.
23
 *
24
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
25
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
26
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
27
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
28
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
29
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
30
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31
 */
32
33
#if !HAVE_ARC4RANDOM || defined(__linux__)
34
35
#include <inttypes.h>
36
#include <stdio.h>
37
38
#include <isc/os.h>
39
#include <isc/random.h>
40
#include <isc/thread.h>
41
#include <isc/util.h>
42
#include <isc/uv.h>
43
44
0
#define ISC_RANDOM_BUFSIZE (ISC_OS_CACHELINE_SIZE / sizeof(uint32_t))
45
46
thread_local static uint32_t isc__random_pool[ISC_RANDOM_BUFSIZE];
47
thread_local static size_t isc__random_pos = ISC_RANDOM_BUFSIZE;
48
49
uint32_t
50
8.86M
isc_random32(void) {
51
8.86M
#if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
52
  /*
53
   * A fixed stream of numbers helps with problem reproduction when
54
   * fuzzing.  The first result needs to be non-zero as expected by
55
   * random_test.c (it starts with ISC_RANDOM_BUFSIZE, see above).
56
   */
57
8.86M
  return (uint32_t)(isc__random_pos++);
58
0
#endif /* if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
59
60
0
  if (isc__random_pos == ISC_RANDOM_BUFSIZE) {
61
0
    isc_random_buf(isc__random_pool, sizeof(isc__random_pool));
62
0
    isc__random_pos = 0;
63
0
  }
64
65
0
  return isc__random_pool[isc__random_pos++];
66
8.86M
}
67
68
void
69
0
isc_random_buf(void *buf, size_t buflen) {
70
0
  REQUIRE(buflen == 0 || buf != NULL);
71
72
0
  if (buf == NULL || buflen == 0) {
73
0
    return;
74
0
  }
75
76
0
  int r = uv_random(NULL, NULL, buf, buflen, 0, NULL);
77
0
  UV_RUNTIME_CHECK(uv_random, r);
78
0
}
79
80
uint32_t
81
8.86M
isc_random_uniform(uint32_t limit) {
82
  /*
83
   * Daniel Lemire's nearly-divisionless unbiased bounded random numbers.
84
   *
85
   * https://lemire.me/blog/?p=17551
86
   *
87
   * The raw random number generator `next()` returns a 32-bit value.
88
   * We do a 64-bit multiply `next() * limit` and treat the product as a
89
   * 32.32 fixed-point value less than the limit. Our result will be the
90
   * integer part (upper 32 bits), and we will use the fraction part
91
   * (lower 32 bits) to determine whether or not we need to resample.
92
   */
93
8.86M
  uint64_t num = (uint64_t)isc_random32() * (uint64_t)limit;
94
  /*
95
   * In the fast path, we avoid doing a division in most cases by
96
   * comparing the fraction part of `num` with the limit, which is
97
   * a slight over-estimate for the exact resample threshold.
98
   */
99
8.86M
  if ((uint32_t)(num) < limit) {
100
    /*
101
     * We are in the slow path where we re-do the approximate test
102
     * more accurately. The exact threshold for the resample loop
103
     * is the remainder after dividing the raw RNG limit `1 << 32`
104
     * by the caller's limit. We use a trick to calculate it
105
     * within 32 bits:
106
     *
107
     *     (1 << 32) % limit
108
     * == ((1 << 32) - limit) % limit
109
     * ==  (uint32_t)(-limit) % limit
110
     *
111
     * This division is safe: we know that `limit` is strictly
112
     * greater than zero because of the slow-path test above.
113
     */
114
1
    uint32_t residue = (uint32_t)(-limit) % limit;
115
    /*
116
     * Unless we get one of `N = (1 << 32) - residue` valid
117
     * values, we reject the sample. This `N` is a multiple of
118
     * `limit`, so our results will be unbiased; and `N` is the
119
     * largest multiple that fits in 32 bits, so rejections are as
120
     * rare as possible.
121
     *
122
     * There are `limit` possible values for the integer part of
123
     * our fixed-point number. Each one corresponds to `N/limit`
124
     * or `N/limit + 1` possible fraction parts. For our result to
125
     * be unbiased, every possible integer part must have the same
126
     * number of possible valid fraction parts. So, when we get
127
     * the superfluous value in the `N/limit + 1` cases, we need
128
     * to reject and resample.
129
     *
130
     * Because of the multiplication, the possible values in the
131
     * fraction part are equally spaced by `limit`, with varying
132
     * gaps at each end of the fraction's 32-bit range. We will
133
     * choose a range of size `N` (a multiple of `limit`) into
134
     * which valid fraction values must fall, with the rest of the
135
     * 32-bit range covered by the `residue`. Lemire's paper says
136
     * that exactly `N/limit` possible values spaced apart by
137
     * `limit` will fit into our size `N` valid range, regardless
138
     * of the size of the end gaps, the phase alignment of the
139
     * values, or the position of the range.
140
     *
141
     * So, when a fraction value falls in the `residue` outside
142
     * our valid range, it is superfluous, and we resample.
143
     */
144
1
    while ((uint32_t)(num) < residue) {
145
0
      num = (uint64_t)isc_random32() * (uint64_t)limit;
146
0
    }
147
1
  }
148
  /*
149
   * Return the integer part (upper 32 bits).
150
   */
151
8.86M
  return (uint32_t)(num >> 32);
152
8.86M
}
153
154
#endif /* HAVE_ARC4RANDOM && !defined(__linux__) */