Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

random: add helpers for random numbers with given floor or range

Now that we have get_random_u32_below(), it's nearly trivial to make
inline helpers to compute get_random_u32_above() and
get_random_u32_inclusive(), which will help clean up open coded loops
and manual computations throughout the tree.

One snag is that in order to make get_random_u32_inclusive() operate on
closed intervals, we have to do some (unlikely) special case handling if
get_random_u32_inclusive(0, U32_MAX) is called. The least expensive way
of doing this is actually to adjust the slowpath of
get_random_u32_below() to have its undefined 0 result just return the
output of get_random_u32(). We can make this basically free by calling
get_random_u32() before the branch, so that the branch latency gets
interleaved.

Cc: stable@vger.kernel.org # to ease future backports that use this api
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>

+42 -1
+17 -1
drivers/char/random.c
··· 161 161 * u16 get_random_u16() 162 162 * u32 get_random_u32() 163 163 * u32 get_random_u32_below(u32 ceil) 164 + * u32 get_random_u32_above(u32 floor) 165 + * u32 get_random_u32_inclusive(u32 floor, u32 ceil) 164 166 * u64 get_random_u64() 165 167 * unsigned long get_random_long() 166 168 * ··· 524 522 * of `-ceil % ceil` is analogous to `2^32 % ceil`, but is computable 525 523 * in 32-bits. 526 524 */ 527 - u64 mult = (u64)ceil * get_random_u32(); 525 + u32 rand = get_random_u32(); 526 + u64 mult; 527 + 528 + /* 529 + * This function is technically undefined for ceil == 0, and in fact 530 + * for the non-underscored constant version in the header, we build bug 531 + * on that. But for the non-constant case, it's convenient to have that 532 + * evaluate to being a straight call to get_random_u32(), so that 533 + * get_random_u32_inclusive() can work over its whole range without 534 + * undefined behavior. 535 + */ 536 + if (unlikely(!ceil)) 537 + return rand; 538 + 539 + mult = (u64)ceil * rand; 528 540 if (unlikely((u32)mult < ceil)) { 529 541 u32 bound = -ceil % ceil; 530 542 while (unlikely((u32)mult < bound))
+25
include/linux/random.h
··· 92 92 } 93 93 94 94 /* 95 + * Returns a random integer in the interval (floor, U32_MAX], with uniform 96 + * distribution, suitable for all uses. Fastest when floor is a constant, but 97 + * still fast for variable floor as well. 98 + */ 99 + static inline u32 get_random_u32_above(u32 floor) 100 + { 101 + BUILD_BUG_ON_MSG(__builtin_constant_p(floor) && floor == U32_MAX, 102 + "get_random_u32_above() must take floor < U32_MAX"); 103 + return floor + 1 + get_random_u32_below(U32_MAX - floor); 104 + } 105 + 106 + /* 107 + * Returns a random integer in the interval [floor, ceil], with uniform 108 + * distribution, suitable for all uses. Fastest when floor and ceil are 109 + * constant, but still fast for variable floor and ceil as well. 110 + */ 111 + static inline u32 get_random_u32_inclusive(u32 floor, u32 ceil) 112 + { 113 + BUILD_BUG_ON_MSG(__builtin_constant_p(floor) && __builtin_constant_p(ceil) && 114 + (floor > ceil || ceil - floor == U32_MAX), 115 + "get_random_u32_inclusive() must take floor <= ceil"); 116 + return floor + get_random_u32_below(ceil - floor + 1); 117 + } 118 + 119 + /* 95 120 * On 64-bit architectures, protect against non-terminated C string overflows 96 121 * by zeroing out the first byte of the canary; this leaves 56 bits of entropy. 97 122 */