* [PATCH v2] random: add helpers for random numbers with given floor or range
@ 2022-11-17 16:35 Jason A. Donenfeld
2022-11-17 16:41 ` Randy Dunlap
0 siblings, 1 reply; 4+ messages in thread
From: Jason A. Donenfeld @ 2022-11-17 16:35 UTC (permalink / raw)
To: linux-kernel, tytso, kees, linux, ydroneaud, gregkh; +Cc: Jason A. Donenfeld
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_interval(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().
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
Changes v1->v2:
- Rename get_random_u32_between() to get_random_u32_inclusive(), and
make it a closed interval.
drivers/char/random.c | 17 ++++++++++++++++-
include/linux/random.h | 25 +++++++++++++++++++++++++
2 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 6f323344d0b9..140dbd557dbc 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -161,6 +161,8 @@ EXPORT_SYMBOL(wait_for_random_bytes);
* u16 get_random_u16()
* u32 get_random_u32()
* u32 get_random_u32_below(u32 ceil)
+ * u32 get_random_u32_above(u32 floor)
+ * u32 get_random_u32_inclusive(u32 ceil, u32 floor)
* u64 get_random_u64()
* unsigned long get_random_long()
*
@@ -522,7 +524,20 @@ u32 __get_random_u32_below(u32 ceil)
* of `-ceil % ceil` is analogous to `2^32 % ceil`, but is computable
* in 32-bits.
*/
- u64 mult = (u64)ceil * get_random_u32();
+ u64 mult;
+
+ /*
+ * This function is technically undefined for ceil == 0, and in fact
+ * for the non-underscored constant version in the header, we build bug
+ * on that. But for the non-constant case, it's convenient to have that
+ * evaluate to being a straight call to get_random_u32(), so that
+ * get_random_u32_inclusive() can work over its whole range without
+ * undefined behavior.
+ */
+ if (unlikely(!ceil))
+ return get_random_u32();
+
+ mult = (u64)ceil * get_random_u32();
if (unlikely((u32)mult < ceil)) {
u32 bound = -ceil % ceil;
while (unlikely((u32)mult < bound))
diff --git a/include/linux/random.h b/include/linux/random.h
index 3a82c0a8bc46..bd954ecbef90 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -91,6 +91,31 @@ static inline u32 get_random_u32_below(u32 ceil)
}
}
+/*
+ * Returns a random integer in the interval (floor, U32_MAX], with uniform
+ * distribution, suitable for all uses. Fastest when floor is a constant, but
+ * still fast for variable floor as well.
+ */
+static inline u32 get_random_u32_above(u32 floor)
+{
+ BUILD_BUG_ON_MSG(__builtin_constant_p(floor) && floor == U32_MAX,
+ "get_random_u32_above() must take floor < U32_MAX");
+ return floor + 1 + get_random_u32_below(U32_MAX - floor);
+}
+
+/*
+ * Returns a random integer in the interval [floor, ceil], with uniform
+ * distribution, suitable for all uses. Fastest when floor and ceil are
+ * constant, but still fast for variable floor and ceil as well.
+ */
+static inline u32 get_random_u32_inclusive(u32 floor, u32 ceil)
+{
+ BUILD_BUG_ON_MSG(__builtin_constant_p(floor) && __builtin_constant_p(ceil) &&
+ (floor > ceil || ceil - floor == U32_MAX),
+ "get_random_u32_inclusive() must take floor <= ceil");
+ return floor + get_random_u32_below(ceil - floor + 1);
+}
+
/*
* On 64-bit architectures, protect against non-terminated C string overflows
* by zeroing out the first byte of the canary; this leaves 56 bits of entropy.
--
2.38.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2] random: add helpers for random numbers with given floor or range
2022-11-17 16:35 [PATCH v2] random: add helpers for random numbers with given floor or range Jason A. Donenfeld
@ 2022-11-17 16:41 ` Randy Dunlap
2022-11-17 19:26 ` [PATCH v3] " Jason A. Donenfeld
0 siblings, 1 reply; 4+ messages in thread
From: Randy Dunlap @ 2022-11-17 16:41 UTC (permalink / raw)
To: Jason A. Donenfeld, linux-kernel, tytso, kees, linux, ydroneaud, gregkh
On 11/17/22 08:35, Jason A. Donenfeld wrote:
> diff --git a/drivers/char/random.c b/drivers/char/random.c
> index 6f323344d0b9..140dbd557dbc 100644
> --- a/drivers/char/random.c
> +++ b/drivers/char/random.c
> @@ -161,6 +161,8 @@ EXPORT_SYMBOL(wait_for_random_bytes);
> * u16 get_random_u16()
> * u32 get_random_u32()
> * u32 get_random_u32_below(u32 ceil)
> + * u32 get_random_u32_above(u32 floor)
> + * u32 get_random_u32_inclusive(u32 ceil, u32 floor)
floor, ceil)
> * u64 get_random_u64()
> * unsigned long get_random_long()
--
~Randy
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v3] random: add helpers for random numbers with given floor or range
2022-11-17 16:41 ` Randy Dunlap
@ 2022-11-17 19:26 ` Jason A. Donenfeld
2022-11-17 21:48 ` Kees Cook
0 siblings, 1 reply; 4+ messages in thread
From: Jason A. Donenfeld @ 2022-11-17 19:26 UTC (permalink / raw)
To: linux-kernel, tytso, kees, linux, ydroneaud, gregkh, rdunlap
Cc: Jason A. Donenfeld
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_interval(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.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
v2->v3:
- Fix doc comment argument order.
- Interleave !ceil check with get_random_u32() call to make branch ~free.
drivers/char/random.c | 18 +++++++++++++++++-
include/linux/random.h | 25 +++++++++++++++++++++++++
2 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 6f323344d0b9..f5868dddbb61 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -161,6 +161,8 @@ EXPORT_SYMBOL(wait_for_random_bytes);
* u16 get_random_u16()
* u32 get_random_u32()
* u32 get_random_u32_below(u32 ceil)
+ * u32 get_random_u32_above(u32 floor)
+ * u32 get_random_u32_inclusive(u32 floor, u32 ceil)
* u64 get_random_u64()
* unsigned long get_random_long()
*
@@ -522,7 +524,21 @@ u32 __get_random_u32_below(u32 ceil)
* of `-ceil % ceil` is analogous to `2^32 % ceil`, but is computable
* in 32-bits.
*/
- u64 mult = (u64)ceil * get_random_u32();
+ u32 rand = get_random_u32();
+ u64 mult;
+
+ /*
+ * This function is technically undefined for ceil == 0, and in fact
+ * for the non-underscored constant version in the header, we build bug
+ * on that. But for the non-constant case, it's convenient to have that
+ * evaluate to being a straight call to get_random_u32(), so that
+ * get_random_u32_inclusive() can work over its whole range without
+ * undefined behavior.
+ */
+ if (unlikely(!ceil))
+ return rand;
+
+ mult = (u64)ceil * rand;
if (unlikely((u32)mult < ceil)) {
u32 bound = -ceil % ceil;
while (unlikely((u32)mult < bound))
diff --git a/include/linux/random.h b/include/linux/random.h
index 3a82c0a8bc46..bd954ecbef90 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -91,6 +91,31 @@ static inline u32 get_random_u32_below(u32 ceil)
}
}
+/*
+ * Returns a random integer in the interval (floor, U32_MAX], with uniform
+ * distribution, suitable for all uses. Fastest when floor is a constant, but
+ * still fast for variable floor as well.
+ */
+static inline u32 get_random_u32_above(u32 floor)
+{
+ BUILD_BUG_ON_MSG(__builtin_constant_p(floor) && floor == U32_MAX,
+ "get_random_u32_above() must take floor < U32_MAX");
+ return floor + 1 + get_random_u32_below(U32_MAX - floor);
+}
+
+/*
+ * Returns a random integer in the interval [floor, ceil], with uniform
+ * distribution, suitable for all uses. Fastest when floor and ceil are
+ * constant, but still fast for variable floor and ceil as well.
+ */
+static inline u32 get_random_u32_inclusive(u32 floor, u32 ceil)
+{
+ BUILD_BUG_ON_MSG(__builtin_constant_p(floor) && __builtin_constant_p(ceil) &&
+ (floor > ceil || ceil - floor == U32_MAX),
+ "get_random_u32_inclusive() must take floor <= ceil");
+ return floor + get_random_u32_below(ceil - floor + 1);
+}
+
/*
* On 64-bit architectures, protect against non-terminated C string overflows
* by zeroing out the first byte of the canary; this leaves 56 bits of entropy.
--
2.38.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v3] random: add helpers for random numbers with given floor or range
2022-11-17 19:26 ` [PATCH v3] " Jason A. Donenfeld
@ 2022-11-17 21:48 ` Kees Cook
0 siblings, 0 replies; 4+ messages in thread
From: Kees Cook @ 2022-11-17 21:48 UTC (permalink / raw)
To: Jason A. Donenfeld
Cc: linux-kernel, tytso, kees, linux, ydroneaud, gregkh, rdunlap
On Thu, Nov 17, 2022 at 08:26:20PM +0100, Jason A. Donenfeld wrote:
> 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_interval(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.
>
> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
I really like these -- unambiguous! :) Thanks for adjusting this API.
Reviewed-by: Kees Cook <keescook@chromium.org>
-Kees
--
Kees Cook
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2022-11-17 21:48 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-17 16:35 [PATCH v2] random: add helpers for random numbers with given floor or range Jason A. Donenfeld
2022-11-17 16:41 ` Randy Dunlap
2022-11-17 19:26 ` [PATCH v3] " Jason A. Donenfeld
2022-11-17 21:48 ` Kees Cook
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.