Re: [PATCH v1 0/5] treewide cleanup of random integer usage
From: Kees Cook <hidden>
Date: 2022-10-06 06:30:21
Also in:
dri-devel, linux-f2fs-devel, linux-hams, linux-nvme, lvs-devel
On Wed, Oct 05, 2022 at 11:48:39PM +0200, Jason A. Donenfeld wrote:
Hi folks,
This is a five part treewide cleanup of random integer handling. The
rules for random integers are:
- If you want a secure or an insecure random u64, use get_random_u64().
- If you want a secure or an insecure random u32, use get_random_u32().
* The old function prandom_u32() has been deprecated for a while now
and is just a wrapper around get_random_u32().
- If you want a secure or an insecure random u16, use get_random_u16().
- If you want a secure or an insecure random u8, use get_random_u8().
- If you want secure or insecure random bytes, use get_random_bytes().
* The old function prandom_bytes() has been deprecated for a while now
and has long been a wrapper around get_random_bytes().
- If you want a non-uniform random u32, u16, or u8 bounded by a certain
open interval maximum, use prandom_u32_max().
* I say "non-uniform", because it doesn't do any rejection sampling or
divisions. Hence, it stays within the prandom_* namespace.
These rules ought to be applied uniformly, so that we can clean up the
deprecated functions, and earn the benefits of using the modern
functions. In particular, in addition to the boring substitutions, this
patchset accomplishes a few nice effects:
- By using prandom_u32_max() with an upper-bound that the compiler can
prove at compile-time is ≤65536 or ≤256, internally get_random_u16()
or get_random_u8() is used, which wastes fewer batched random bytes,
and hence has higher throughput.
- By using prandom_u32_max() instead of %, when the upper-bound is not a
constant, division is still avoided, because prandom_u32_max() uses
a faster multiplication-based trick instead.
- By using get_random_u16() or get_random_u8() in cases where the return
value is intended to indeed be a u16 or a u8, we waste fewer batched
random bytes, and hence have higher throughput.
So, based on those rules and benefits from following them, this patchset
breaks down into the following five steps:
1) Replace `prandom_u32() % max` and variants thereof with
prandom_u32_max(max).
2) Replace `(type)get_random_u32()` and variants thereof with
get_random_u16() or get_random_u8(). I took the pains to actually
look and see what every lvalue type was across the entire tree.
3) Replace remaining deprecated uses of prandom_u32() with
get_random_u32().
4) Replace remaining deprecated uses of prandom_bytes() with
get_random_bytes().
5) Remove the deprecated and now-unused prandom_u32() and
prandom_bytes() inline wrapper functions.
I was thinking of taking this through my random.git tree (on which this
series is currently based) and submitting it near the end of the merge
window, or waiting for the very end of the 6.1 cycle when there will be
the fewest new patches brewing. If somebody with some treewide-cleanup
experience might share some wisdom about what the best timing usually
winds up being, I'm all ears.It'd be nice to capture some (all?) of the above somewhere. Perhaps just a massive comment in the header?
I've CC'd get_maintainers.pl, which is a pretty big list. Probably some portion of those are going to bounce, too, and everytime you reply to this thread, you'll have to deal with a bunch of bounces coming immediately after. And a recipient list this big will probably dock my email domain's spam reputation, at least temporarily. Sigh. I think that's just how it goes with treewide cleanups though. Again, let me know if I'm doing it wrong.
I usually stick to just mailing lists and subsystem maintainers. If any of the subsystems ask you to break this up (I hope not), I've got this[1], which does a reasonable job of splitting a commit up into separate commits for each matching subsystem. Showing that a treewide change can be reproduced mechanically helps with keeping it together as one bit treewide patch, too, I've found. :) Thank you for the cleanup! The "u8 rnd = get_random_u32()" in the tree has bothered me for a loooong time. -Kees -- Kees Cook