FAILED: patch "[PATCH] random: fix crash on multiple early calls to" failed to apply to 5.4-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From f7e67b8e803185d0aabe7f29d25a35c8be724a78 Mon Sep 17 00:00:00 2001
From: Dominik Brodowski <[email protected]>
Date: Wed, 29 Dec 2021 22:10:03 +0100
Subject: [PATCH] random: fix crash on multiple early calls to
add_bootloader_randomness()
Currently, if CONFIG_RANDOM_TRUST_BOOTLOADER is enabled, multiple calls to add_bootloader_randomness() are broken and can cause a NULL pointer dereference, as noted by Ivan T. Ivanov. This is not only a hypothetical problem, as qemu on arm64 may provide bootloader entropy via EFI and via devicetree.
On the first call to add_hwgenerator_randomness(), crng_fast_load() is executed, and if the seed is long enough, crng_init will be set to 1. On subsequent calls to add_bootloader_randomness() and then to add_hwgenerator_randomness(), crng_fast_load() will be skipped. Instead, wait_event_interruptible() and then credit_entropy_bits() will be called. If the entropy count for that second seed is large enough, that proceeds to crng_reseed().
However, both wait_event_interruptible() and crng_reseed() depends (at least in numa_crng_init()) on workqueues. Therefore, test whether system_wq is already initialized, which is a sufficient indicator that workqueue_init_early() has progressed far enough.
If we wind up hitting the !system_wq case, we later want to do what would have been done there when wqs are up, so set a flag, and do that work later from the rand_initialize() call.
drivers/char/random.c +36 -20
@@ -468,6 +468,7 @@ static struct crng_state primary_crng = {* its value (from 0->1->2). */ static int crng_init =0 ; +static bool crng_need_final_init = false;#define crng_ready () (likely(crng_init > 1))static int crng_init_cnt =0 ;static unsigned long crng_global_init_time =0 ;
@@ -835,6 +836,36 @@ static void __init crng_initialize_primary(struct crng_state *crng) crng->init_time = jiffies -CRNG_RESEED_INTERVAL -1 ; } +static void crng_finalize_init (struct crng_state *crng) +{ +if (crng != &primary_crng || crng_init >=2 ) +return ; +if (!system_wq) { +/* We can't call numa_crng_init until we have workqueues, +* so mark this for processing later. */ + crng_need_final_init = true; +return ; + } + +invalidate_batched_entropy (); +numa_crng_init (); + crng_init =2 ; +process_random_ready_list (); +wake_up_interruptible (&crng_init_wait); +kill_fasync (&fasync,SIGIO ,POLL_IN ); +pr_notice ("crng init done\n" ); +if (unseeded_warning.missed) { +pr_notice ("%d get_random_xx warning(s) missed due to ratelimiting\n" , + unseeded_warning.missed); + unseeded_warning.missed =0 ; + } +if (urandom_warning.missed) { +pr_notice ("%d urandom warning(s) missed due to ratelimiting\n" , + urandom_warning.missed); + urandom_warning.missed =0 ; + } +} +#ifdef CONFIG_NUMA static void do_numa_crng_init (struct work_struct *work) {
@@ -989,25 +1020,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)memzero_explicit (&buf,sizeof (buf));WRITE_ONCE (crng->init_time, jiffies);spin_unlock_irqrestore (&crng->lock, flags); -if (crng == &primary_crng && crng_init <2 ) { -invalidate_batched_entropy (); -numa_crng_init (); - crng_init =2 ; -process_random_ready_list (); -wake_up_interruptible (&crng_init_wait); -kill_fasync (&fasync,SIGIO ,POLL_IN ); -pr_notice ("crng init done\n" ); -if (unseeded_warning.missed) { -pr_notice ("%d get_random_xx warning(s) missed due to ratelimiting\n" , - unseeded_warning.missed); - unseeded_warning.missed =0 ; - } -if (urandom_warning.missed) { -pr_notice ("%d urandom warning(s) missed due to ratelimiting\n" , - urandom_warning.missed); - urandom_warning.missed =0 ; - } - } +crng_finalize_init (crng); } static void _extract_crng(struct crng_state *crng,
@@ -1780,6 +1793,8 @@ static void __init init_std_data(struct entropy_store *r)int __init rand_initialize (void ) {init_std_data (&input_pool); +if (crng_need_final_init) +crng_finalize_init (&primary_crng);crng_initialize_primary (&primary_crng); crng_global_init_time = jiffies;if (ratelimit_disable) {
@@ -2288,7 +2303,8 @@ void add_hwgenerator_randomness(const char *buffer, size_t count,* We'll be woken up again once below random_write_wakeup_thresh, * or when the calling thread is about to terminate. */ -wait_event_interruptible (random_write_wait,kthread_should_stop () || +wait_event_interruptible (random_write_wait, + !system_wq ||kthread_should_stop () ||ENTROPY_BITS (&input_pool) <= random_write_wakeup_bits);mix_pool_bytes (poolp, buffer, count);credit_entropy_bits (poolp, entropy);
Jason A. Donenfeld
maintainerPATCH 1/1 random: fix crash on multiple early calls to add_bootloader_randomness()
From: Dominik Brodowski <[email protected]>
commit f7e67b8e803185d0aabe7f29d25a35c8be724a78 upstream.
Currently, if CONFIG_RANDOM_TRUST_BOOTLOADER is enabled, multiple calls to add_bootloader_randomness() are broken and can cause a NULL pointer dereference, as noted by Ivan T. Ivanov. This is not only a hypothetical problem, as qemu on arm64 may provide bootloader entropy via EFI and via devicetree.
On the first call to add_hwgenerator_randomness(), crng_fast_load() is executed, and if the seed is long enough, crng_init will be set to 1. On subsequent calls to add_bootloader_randomness() and then to add_hwgenerator_randomness(), crng_fast_load() will be skipped. Instead, wait_event_interruptible() and then credit_entropy_bits() will be called. If the entropy count for that second seed is large enough, that proceeds to crng_reseed().
However, both wait_event_interruptible() and crng_reseed() depends (at least in numa_crng_init()) on workqueues. Therefore, test whether system_wq is already initialized, which is a sufficient indicator that workqueue_init_early() has progressed far enough.
If we wind up hitting the !system_wq case, we later want to do what would have been done there when wqs are up, so set a flag, and do that work later from the rand_initialize() call.
--- drivers/char/random.c | 59 ++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 21 deletions(-)
drivers/char/random.c +38 -21
@@ -497,6 +497,7 @@ static struct crng_state primary_crng = {* its value (from 0->1->2). */ static int crng_init =0 ; +static bool crng_need_final_init = false;#define crng_ready () (likely(crng_init > 1))static int crng_init_cnt =0 ;static unsigned long crng_global_init_time =0 ;
@@ -889,6 +890,38 @@ static void crng_initialize(struct crng_state *crng) crng->init_time = jiffies -CRNG_RESEED_INTERVAL -1 ; } +static void crng_finalize_init (struct crng_state *crng) +{ +if (crng != &primary_crng || crng_init >=2 ) +return ; +if (!system_wq) { +/* We can't call numa_crng_init until we have workqueues, +* so mark this for processing later. */ + crng_need_final_init = true; +return ; + } + +invalidate_batched_entropy (); +numa_crng_init (); + crng_init =2 ; +process_random_ready_list (); +wake_up_interruptible (&crng_init_wait); +kill_fasync (&fasync,SIGIO ,POLL_IN ); +pr_notice ("crng init done\n" ); +if (unseeded_warning.missed) { +pr_notice ("random: %d get_random_xx warning(s) missed " +"due to ratelimiting\n" , + unseeded_warning.missed); + unseeded_warning.missed =0 ; + } +if (urandom_warning.missed) { +pr_notice ("random: %d urandom warning(s) missed " +"due to ratelimiting\n" , + urandom_warning.missed); + urandom_warning.missed =0 ; + } +} +#ifdef CONFIG_NUMA static void do_numa_crng_init (struct work_struct *work) {
@@ -1026,26 +1059,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)memzero_explicit (&buf,sizeof (buf)); crng->init_time = jiffies;spin_unlock_irqrestore (&crng->lock, flags); -if (crng == &primary_crng && crng_init <2 ) { -invalidate_batched_entropy (); -numa_crng_init (); - crng_init =2 ; -process_random_ready_list (); -wake_up_interruptible (&crng_init_wait); -pr_notice ("random: crng init done\n" ); -if (unseeded_warning.missed) { -pr_notice ("random: %d get_random_xx warning(s) missed " -"due to ratelimiting\n" , - unseeded_warning.missed); - unseeded_warning.missed =0 ; - } -if (urandom_warning.missed) { -pr_notice ("random: %d urandom warning(s) missed " -"due to ratelimiting\n" , - urandom_warning.missed); - urandom_warning.missed =0 ; - } - } +crng_finalize_init (crng); } static void _extract_crng(struct crng_state *crng,
@@ -1957,6 +1971,8 @@ int __init rand_initialize(void) {init_std_data (&input_pool);init_std_data (&blocking_pool); +if (crng_need_final_init) +crng_finalize_init (&primary_crng);crng_initialize (&primary_crng); crng_global_init_time = jiffies;if (ratelimit_disable) {
@@ -2488,7 +2504,8 @@ void add_hwgenerator_randomness(const char *buffer, size_t count,* We'll be woken up again once below random_write_wakeup_thresh, * or when the calling thread is about to terminate. */ -wait_event_interruptible (random_write_wait,kthread_should_stop () || +wait_event_interruptible (random_write_wait, + !system_wq ||kthread_should_stop () ||ENTROPY_BITS (&input_pool) <= random_write_wakeup_bits);mix_pool_bytes (poolp, buffer, count);credit_entropy_bits (poolp, entropy);
Signature · 1 line
2.34.1
Greg KH
maintainerRe: [PATCH stable 5.4.y] random: fix crash on multiple early calls to add_bootloader_randomness()
Quoted 33 lines · Jason A. Donenfeld
From: Dominik Brodowski <[email protected]>
commit
f7e67b8e803185d0aabe7f29d25a35c8be724a78upstream.Currently, if
CONFIG_RANDOM_TRUST_BOOTLOADERis enabled, multiple calls toadd_bootloader_randomness()are broken and can cause a NULL pointer dereference, as noted by Ivan T. Ivanov. This is not only a hypothetical problem, as qemu on arm64 may provide bootloader entropy via EFI and via devicetree.On the first call to
add_hwgenerator_randomness(),crng_fast_load()is executed, and if the seed is long enough,crng_initwill be set to 1. On subsequent calls toadd_bootloader_randomness()and then toadd_hwgenerator_randomness(),crng_fast_load()will be skipped. Instead,wait_event_interruptible()and thencredit_entropy_bits()will be called. If the entropy count for that second seed is large enough, that proceeds tocrng_reseed().However, both
wait_event_interruptible()andcrng_reseed()depends (at least innuma_crng_init()) on workqueues. Therefore, test whethersystem_wqis already initialized, which is a sufficient indicator thatworkqueue_init_early()has progressed far enough.If we wind up hitting the !system_wq case, we later want to do what would have been done there when wqs are up, so set a flag, and do that work later from the
rand_initialize()call.Reported-by Ivan T. Ivanov <[email protected]>Fixes 18b915ac6b0a ("efi/random: Treat EFI_RNG_PROTOCOL output as bootloader randomness")Signed-off-by Dominik Brodowski <[email protected]>[Jason: added crng_need_done state and related logic.]Signed-off-by Jason A. Donenfeld <[email protected]>
Quoted 3 lines
--- drivers/char/random.c | 59 ++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 21 deletions(-)
Now queued up, thanks!
greg k-h