Coverage Report

Created: 2025-11-24 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/njs/src/njs_random.c
Line
Count
Source
1
2
/*
3
 * Copyright (C) Igor Sysoev
4
 * Copyright (C) NGINX, Inc.
5
 */
6
7
8
#include <njs_main.h>
9
#if (NJS_HAVE_GETRANDOM)
10
#include <sys/random.h>
11
#elif (NJS_HAVE_CCRANDOMGENERATEBYTES)
12
#include <CommonCrypto/CommonCryptoError.h>
13
#include <CommonCrypto/CommonRandom.h>
14
#elif (NJS_HAVE_LINUX_SYS_GETRANDOM)
15
#include <sys/syscall.h>
16
#include <linux/random.h>
17
#elif (NJS_HAVE_GETENTROPY_SYS_RANDOM)
18
#include <sys/random.h>
19
#endif
20
21
22
/*
23
 * The pseudorandom generator based on OpenBSD arc4random.  Although
24
 * it is usually stated that arc4random uses RC4 pseudorandom generation
25
 * algorithm they are actually different in njs_random_add().
26
 */
27
28
29
0
#define NJS_RANDOM_KEY_SIZE  128
30
31
32
njs_inline uint8_t njs_random_byte(njs_random_t *r);
33
34
35
void
36
njs_random_init(njs_random_t *r, njs_pid_t pid)
37
0
{
38
0
    njs_uint_t  i;
39
40
0
    r->count = 0;
41
0
    r->pid = pid;
42
0
    r->i = 0;
43
0
    r->j = 0;
44
45
0
    for (i = 0; i < 256; i++) {
46
0
        r->s[i] = i;
47
0
    }
48
0
}
49
50
51
void
52
njs_random_stir(njs_random_t *r, njs_pid_t pid)
53
0
{
54
0
    int             fd;
55
0
    ssize_t         n;
56
0
    struct timeval  tv;
57
0
    union {
58
0
        uint32_t    value[3];
59
0
        u_char      bytes[NJS_RANDOM_KEY_SIZE];
60
0
    } key;
61
62
0
    if (r->pid == 0) {
63
0
        njs_random_init(r, pid);
64
0
    }
65
66
0
    r->pid = pid;
67
68
0
#if (NJS_HAVE_GETRANDOM)
69
70
0
    n = getrandom(&key, NJS_RANDOM_KEY_SIZE, 0);
71
72
#elif (NJS_HAVE_LINUX_SYS_GETRANDOM)
73
74
    /* Linux 3.17 SYS_getrandom, not available in Glibc prior to 2.25. */
75
76
    n = syscall(SYS_getrandom, &key, NJS_RANDOM_KEY_SIZE, 0);
77
78
#elif (NJS_HAVE_CCRANDOMGENERATEBYTES)
79
80
    /* Apple discourages the use of getentropy. */
81
82
    n = 0;
83
84
    if (CCRandomGenerateBytes(&key, NJS_RANDOM_KEY_SIZE) == kCCSuccess) {
85
        n = NJS_RANDOM_KEY_SIZE;
86
    }
87
88
#elif (NJS_HAVE_GETENTROPY || NJS_HAVE_GETENTROPY_SYS_RANDOM)
89
90
    n = 0;
91
92
    if (getentropy(&key, NJS_RANDOM_KEY_SIZE) == 0) {
93
        n = NJS_RANDOM_KEY_SIZE;
94
    }
95
96
#else
97
98
    n = 0;
99
100
#endif
101
102
0
    if (n != NJS_RANDOM_KEY_SIZE) {
103
0
        fd = open("/dev/urandom", O_RDONLY);
104
105
0
        if (fd >= 0) {
106
0
            n = read(fd, &key, NJS_RANDOM_KEY_SIZE);
107
0
            (void) close(fd);
108
0
        }
109
0
    }
110
111
0
    if (n != NJS_RANDOM_KEY_SIZE) {
112
0
        (void) gettimeofday(&tv, NULL);
113
114
        /* XOR with stack garbage. */
115
116
0
        key.value[0] ^= tv.tv_usec;
117
0
        key.value[1] ^= tv.tv_sec;
118
0
        key.value[2] ^= getpid();
119
0
    }
120
121
0
    njs_msan_unpoison(&key, NJS_RANDOM_KEY_SIZE);
122
123
0
    njs_random_add(r, key.bytes, NJS_RANDOM_KEY_SIZE);
124
125
    /* Drop the first 3072 bytes. */
126
0
    for (n = 3072; n != 0; n--) {
127
0
        (void) njs_random_byte(r);
128
0
    }
129
130
    /* Stir again after 1,600,000 bytes. */
131
0
    r->count = 400000;
132
0
}
133
134
135
void
136
njs_random_add(njs_random_t *r, const u_char *key, uint32_t len)
137
0
{
138
0
    uint8_t   val;
139
0
    uint32_t  n;
140
141
0
    for (n = 0; n < 256; n++) {
142
0
        val = r->s[r->i];
143
0
        r->j += val + key[n % len];
144
145
0
        r->s[r->i] = r->s[r->j];
146
0
        r->s[r->j] = val;
147
148
0
        r->i++;
149
0
    }
150
151
    /* This index is not decremented in RC4 algorithm. */
152
0
    r->i--;
153
154
0
    r->j = r->i;
155
0
}
156
157
158
uint32_t
159
njs_random(njs_random_t *r)
160
0
{
161
0
    uint32_t    val;
162
0
    njs_pid_t   pid;
163
0
    njs_bool_t  new_pid;
164
165
0
    new_pid = 0;
166
0
    pid = r->pid;
167
168
0
    if (pid != -1) {
169
0
        pid = getpid();
170
171
0
        if (pid != r->pid) {
172
0
            new_pid = 1;
173
0
        }
174
0
    }
175
176
0
    r->count--;
177
178
0
    if (r->count <= 0 || new_pid) {
179
0
        njs_random_stir(r, pid);
180
0
    }
181
182
0
    val  = (uint32_t) njs_random_byte(r) << 24;
183
0
    val |= (uint32_t) njs_random_byte(r) << 16;
184
0
    val |= (uint32_t) njs_random_byte(r) << 8;
185
0
    val |= (uint32_t) njs_random_byte(r);
186
187
0
    return val;
188
0
}
189
190
191
njs_inline uint8_t
192
njs_random_byte(njs_random_t *r)
193
0
{
194
0
    uint8_t  si, sj;
195
196
0
    r->i++;
197
0
    si = r->s[r->i];
198
0
    r->j += si;
199
200
0
    sj = r->s[r->j];
201
0
    r->s[r->i] = sj;
202
0
    r->s[r->j] = si;
203
204
0
    si += sj;
205
206
0
    return r->s[si];
207
0
}