3535
3636static bool srand_called = false;
3737
38- int rdrand (unsigned long * ret ) {
39-
40- /* So, you are a "security researcher", and you wonder why we bother with using raw RDRAND here,
41- * instead of sticking to /dev/urandom or getrandom()?
42- *
43- * Here's why: early boot. On Linux, during early boot the random pool that backs /dev/urandom and
44- * getrandom() is generally not initialized yet. It is very common that initialization of the random
45- * pool takes a longer time (up to many minutes), in particular on embedded devices that have no
46- * explicit hardware random generator, as well as in virtualized environments such as major cloud
47- * installations that do not provide virtio-rng or a similar mechanism.
48- *
49- * In such an environment using getrandom() synchronously means we'd block the entire system boot-up
50- * until the pool is initialized, i.e. *very* long. Using getrandom() asynchronously (GRND_NONBLOCK)
51- * would mean acquiring randomness during early boot would simply fail. Using /dev/urandom would mean
52- * generating many kmsg log messages about our use of it before the random pool is properly
53- * initialized. Neither of these outcomes is desirable.
54- *
55- * Thus, for very specific purposes we use RDRAND instead of either of these three options. RDRAND
56- * provides us quickly and relatively reliably with random values, without having to delay boot,
57- * without triggering warning messages in kmsg.
58- *
59- * Note that we use RDRAND only under very specific circumstances, when the requirements on the
60- * quality of the returned entropy permit it. Specifically, here are some cases where we *do* use
61- * RDRAND:
62- *
63- * • UUID generation: UUIDs are supposed to be universally unique but are not cryptographic
64- * key material. The quality and trust level of RDRAND should hence be OK: UUIDs should be
65- * generated in a way that is reliably unique, but they do not require ultimate trust into
66- * the entropy generator. systemd generates a number of UUIDs during early boot, including
67- * 'invocation IDs' for every unit spawned that identify the specific invocation of the
68- * service globally, and a number of others. Other alternatives for generating these UUIDs
69- * have been considered, but don't really work: for example, hashing uuids from a local
70- * system identifier combined with a counter falls flat because during early boot disk
71- * storage is not yet available (think: initrd) and thus a system-specific ID cannot be
72- * stored or retrieved yet.
73- *
74- * • Hash table seed generation: systemd uses many hash tables internally. Hash tables are
75- * generally assumed to have O(1) access complexity, but can deteriorate to prohibitive
76- * O(n) access complexity if an attacker manages to trigger a large number of hash
77- * collisions. Thus, systemd (as any software employing hash tables should) uses seeded
78- * hash functions for its hash tables, with a seed generated randomly. The hash tables
79- * systemd employs watch the fill level closely and reseed if necessary. This allows use of
80- * a low quality RNG initially, as long as it improves should a hash table be under attack:
81- * the attacker after all needs to trigger many collisions to exploit it for the purpose
82- * of DoS, but if doing so improves the seed the attack surface is reduced as the attack
83- * takes place.
84- *
85- * Some cases where we do NOT use RDRAND are:
86- *
87- * • Generation of cryptographic key material 🔑
88- *
89- * • Generation of cryptographic salt values 🧂
90- *
91- * This function returns:
92- *
93- * -EOPNOTSUPP → RDRAND is not available on this system 😔
94- * -EAGAIN → The operation failed this time, but is likely to work if you try again a few
95- * times ♻
96- * -EUCLEAN → We got some random value, but it looked strange, so we refused using it.
97- * This failure might or might not be temporary. 😕
98- */
99-
100- #if defined(__i386__ ) || defined(__x86_64__ )
101- static int have_rdrand = -1 ;
102- unsigned long v ;
103- uint8_t success ;
104-
105- if (have_rdrand < 0 ) {
106- uint32_t eax , ebx , ecx , edx ;
107-
108- /* Check if RDRAND is supported by the CPU */
109- if (__get_cpuid (1 , & eax , & ebx , & ecx , & edx ) == 0 ) {
110- have_rdrand = false;
111- return - EOPNOTSUPP ;
112- }
113-
114- /* Compat with old gcc where bit_RDRND didn't exist yet */
115- #ifndef bit_RDRND
116- #define bit_RDRND (1U << 30)
117- #endif
118-
119- have_rdrand = !!(ecx & bit_RDRND );
120-
121- if (have_rdrand > 0 ) {
122- /* Allow disabling use of RDRAND with SYSTEMD_RDRAND=0
123- If it is unset getenv_bool_secure will return a negative value. */
124- if (getenv_bool_secure ("SYSTEMD_RDRAND" ) == 0 ) {
125- have_rdrand = false;
126- return - EOPNOTSUPP ;
127- }
128- }
129- }
130-
131- if (have_rdrand == 0 )
132- return - EOPNOTSUPP ;
133-
134- asm volatile ("rdrand %0;"
135- "setc %1"
136- : "=r" (v ),
137- "=qm" (success ));
138- msan_unpoison (& success , sizeof (success ));
139- if (!success )
140- return - EAGAIN ;
141-
142- /* Apparently on some AMD CPUs RDRAND will sometimes (after a suspend/resume cycle?) report success
143- * via the carry flag but nonetheless return the same fixed value -1 in all cases. This appears to be
144- * a bad bug in the CPU or firmware. Let's deal with that and work-around this by explicitly checking
145- * for this special value (and also 0, just to be sure) and filtering it out. This is a work-around
146- * only however and something AMD really should fix properly. The Linux kernel should probably work
147- * around this issue by turning off RDRAND altogether on those CPUs. See:
148- * https://github.com/systemd/systemd/issues/11810 */
149- if (v == 0 || v == ULONG_MAX )
150- return log_debug_errno (SYNTHETIC_ERRNO (EUCLEAN ),
151- "RDRAND returned suspicious value %lx, assuming bad hardware RNG, not using value." , v );
152-
153- * ret = v ;
154- return 0 ;
155- #else
156- return - EOPNOTSUPP ;
157- #endif
158- }
159-
16038int genuine_random_bytes (void * p , size_t n , RandomFlags flags ) {
16139 static int have_syscall = -1 ;
16240 _cleanup_close_ int fd = -1 ;
16341
164- if (FLAGS_SET (flags , RANDOM_BLOCK | RANDOM_ALLOW_RDRAND ))
165- return - EINVAL ;
166-
167- /* Gathers some high-quality randomness from the kernel (or potentially mid-quality randomness from
168- * the CPU if the RANDOM_ALLOW_RDRAND flag is set). This call won't block, unless the RANDOM_BLOCK
42+ /* Gathers some high-quality randomness from the kernel. This call won't block, unless the RANDOM_BLOCK
16943 * flag is set. If it doesn't block, it will still always return some data from the kernel, regardless
17044 * of whether the random pool is fully initialized or not. When creating cryptographic key material you
17145 * should always use RANDOM_BLOCK. */
@@ -212,34 +86,6 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
21286 }
21387 }
21488
215- if (FLAGS_SET (flags , RANDOM_ALLOW_RDRAND )) {
216- /* Try x86-64' RDRAND intrinsic if we have it. We only use it if high quality randomness is
217- * not required, as we don't trust it (who does?). Note that we only do a single iteration of
218- * RDRAND here, even though the Intel docs suggest calling this in a tight loop of 10
219- * invocations or so. That's because we don't really care about the quality here. We
220- * generally prefer using RDRAND if the caller allows us to, since this way we won't upset
221- * the kernel's random subsystem by accessing it before the pool is initialized (after all it
222- * will kmsg log about every attempt to do so). */
223- for (;;) {
224- unsigned long u ;
225- size_t m ;
226-
227- if (rdrand (& u ) < 0 ) {
228- /* OK, this didn't work, let's go with /dev/urandom instead */
229- break ;
230- }
231-
232- m = MIN (sizeof (u ), n );
233- memcpy (p , & u , m );
234-
235- p = (uint8_t * ) p + m ;
236- n -= m ;
237-
238- if (n == 0 )
239- return 0 ; /* Yay, success! */
240- }
241- }
242-
24389 fd = open ("/dev/urandom" , O_RDONLY |O_CLOEXEC |O_NOCTTY );
24490 if (fd < 0 )
24591 return errno == ENOENT ? - ENOSYS : - errno ;
@@ -257,8 +103,6 @@ void initialize_srand(void) {
257103#if HAVE_SYS_AUXV_H
258104 const void * auxv ;
259105#endif
260- unsigned long k ;
261-
262106 if (srand_called )
263107 return ;
264108
@@ -283,9 +127,6 @@ void initialize_srand(void) {
283127 x ^= (unsigned ) now (CLOCK_REALTIME );
284128 x ^= (unsigned ) gettid ();
285129
286- if (rdrand (& k ) >= 0 )
287- x ^= (unsigned ) k ;
288-
289130 srand (x );
290131 srand_called = true;
291132
@@ -339,8 +180,8 @@ void random_bytes(void *p, size_t n) {
339180 *
340181 * What this function will do:
341182 *
342- * • This function will preferably use the CPU's RDRAND operation, if it is available, in
343- * order to return "mid -quality" random values cheaply .
183+ * • Use getrandom(GRND_INSECURE) or /dev/urandom, to return high-quality random values if
184+ * they are cheaply available, or less high -quality random values if they are not .
344185 *
345186 * • This function will return pseudo-random data, generated via libc rand() if nothing
346187 * better is available.
@@ -363,7 +204,7 @@ void random_bytes(void *p, size_t n) {
363204 * This function is hence not useful for generating UUIDs or cryptographic key material.
364205 */
365206
366- if (genuine_random_bytes (p , n , RANDOM_ALLOW_RDRAND ) >= 0 )
207+ if (genuine_random_bytes (p , n , 0 ) >= 0 )
367208 return ;
368209
369210 /* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */
0 commit comments