Skip to content

Commit d56b576

Browse files
committed
crypto: rng - Make the per-CPU DRBG instances permanent
The per-CPU DRBG instances used to be torn down by crypto_del_default_rng() under del_pcpu_rwsem, and the read path took that rwsem as a reader to keep an instance from being freed out from under it. That machinery only made sense back when the extrng override could be unregistered and the DRBG could be built as a module. That's no longer the case. extrng registration is now restricted to init time from built-in drivers, and FIPS mode requires the DRBG to be built-in, so the registered DRBG can't be unregistered or swapped out. As such, the per-CPU instances are never torn down, and the deletion rwsem just adds a lock to the hot read path for no reason. Drop the deletion rwsem and crypto_del_pcpu_rng(), and stop freeing the per-CPU instances in crypto_del_default_rng(). Since the instances are permanent now, allocate their pages once at init time with __GFP_NOFAIL and ditch free_pcpu_inst() along with the failure paths in crypto_rng_init(); failing to install the RNG override in FIPS mode would be catastrophic, so the setup isn't allowed to fail anyway. This brings the per-CPU DRBG implementation in line with the ciqlts9_6 tree's version of "crypto: rng - Implement fast per-CPU DRBG instances" [1]. [1] b0c560a Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Sultan Alsawaf <sultan@ciq.com>
1 parent 741af30 commit d56b576

1 file changed

Lines changed: 18 additions & 88 deletions

File tree

crypto/rng.c

Lines changed: 18 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -188,24 +188,6 @@ void crypto_put_default_rng(void)
188188
EXPORT_SYMBOL_GPL(crypto_put_default_rng);
189189

190190
#if defined(CONFIG_CRYPTO_RNG) || defined(CONFIG_CRYPTO_RNG_MODULE)
191-
#define down_read_del_pcpu_rwsem() down_read(&del_pcpu_rwsem)
192-
#define up_read_del_pcpu_rwsem() up_read(&del_pcpu_rwsem)
193-
static DECLARE_RWSEM(del_pcpu_rwsem);
194-
195-
static void crypto_del_pcpu_rng(struct cpu_rng_inst __percpu *pcri)
196-
{
197-
int cpu;
198-
199-
for_each_possible_cpu(cpu) {
200-
struct cpu_rng_inst *cri = per_cpu_ptr(pcri, cpu);
201-
202-
if (cri->rng) {
203-
crypto_free_rng(cri->rng);
204-
cri->rng = NULL;
205-
}
206-
}
207-
}
208-
209191
int crypto_del_default_rng(void)
210192
{
211193
bool busy;
@@ -216,26 +198,10 @@ int crypto_del_default_rng(void)
216198
crypto_default_rng = NULL;
217199
}
218200
rt_mutex_unlock(&crypto_default_rng_lock);
219-
if (busy)
220-
return -EBUSY;
221201

222-
if (!down_write_trylock(&del_pcpu_rwsem))
223-
return -EBUSY;
224-
225-
crypto_del_pcpu_rng(&pcpu_default_rng);
226-
crypto_del_pcpu_rng(&pcpu_reseed_rng);
227-
up_write(&del_pcpu_rwsem);
228-
229-
return 0;
202+
return busy ? -EBUSY : 0;
230203
}
231204
EXPORT_SYMBOL_GPL(crypto_del_default_rng);
232-
#else
233-
static inline void down_read_del_pcpu_rwsem(void)
234-
{
235-
}
236-
static inline void up_read_del_pcpu_rwsem(void)
237-
{
238-
}
239205
#endif
240206

241207
static void rng_default_set_ent(struct crypto_rng *tfm, const u8 *data,
@@ -346,13 +312,10 @@ lock_default_rng(struct crypto_rng **rng) __acquires(&cri->lock)
346312
local_lock(&pcri->lock);
347313
cri = this_cpu_ptr(pcri);
348314
/*
349-
* cri->rng may have transitioned from non-NULL to NULL, but
350-
* underneath down_read_del_pcpu_rwsem() it can only transition
351-
* from NULL to non-NULL. This may occur on a different CPU,
352-
* thus cri->rng must be read atomically to prevent data races;
353-
* this elides mlock by pairing with the WRITE_ONCE() in the
354-
* slow path below.
355-
*
315+
* cri->rng can only transition from NULL to non-NULL. This may
316+
* occur on a different CPU, thus cri->rng must be read
317+
* atomically to prevent data races; this elides mlock by
318+
* pairing with the WRITE_ONCE() in the slow path below.
356319
*
357320
* And if cri->rng is non-NULL, then it is good to go. To avoid
358321
* data races due to load speculation on torn cri->rng loads
@@ -490,8 +453,6 @@ static ssize_t crypto_devrandom_read_iter(struct iov_iter *iter, bool reseed)
490453
}
491454
}
492455

493-
/* Prevent rngs from getting deleted from per-CPU RNG instances */
494-
down_read_del_pcpu_rwsem();
495456
restart:
496457
/*
497458
* Pin the user page backing the current user destination address,
@@ -502,7 +463,7 @@ static ssize_t crypto_devrandom_read_iter(struct iov_iter *iter, bool reseed)
502463
*/
503464
if (user_no_reseed && pin_user_pages_fast((unsigned long)uaddr, 1,
504465
FOLL_WRITE, &upage) != 1)
505-
goto up_rwsem;
466+
goto exit;
506467

507468
cri = lock_local_rng(&rng, reseed);
508469
if (IS_ERR(cri)) {
@@ -657,72 +618,41 @@ static ssize_t crypto_devrandom_read_iter(struct iov_iter *iter, bool reseed)
657618
unpin_upage:
658619
if (user_no_reseed)
659620
unpin_user_page(upage);
660-
up_rwsem:
661-
up_read_del_pcpu_rwsem();
662-
return ret ? ret : -EFAULT;
621+
exit:
622+
return ret ? ret : -EFAULT;
663623
}
664624

665625
static const struct random_extrng crypto_devrandom_rng = {
666626
.extrng_read_iter = crypto_devrandom_read_iter
667627
};
668628

669-
static void free_pcpu_inst(struct cpu_rng_inst __percpu *pcri)
629+
static void __init alloc_pcpu_inst(struct cpu_rng_inst __percpu *pcri)
670630
{
671631
int cpu;
672632

673633
for_each_possible_cpu(cpu) {
674634
struct cpu_rng_inst *cri = per_cpu_ptr(pcri, cpu);
675635

676-
if (cri->rng)
677-
crypto_free_rng(cri->rng);
678-
679-
free_page((unsigned long)cri->page);
680-
}
681-
}
682-
683-
static int __init alloc_pcpu_inst(struct cpu_rng_inst __percpu *pcri)
684-
{
685-
int cpu;
686-
687-
for_each_possible_cpu(cpu) {
688-
struct cpu_rng_inst *cri = per_cpu_ptr(pcri, cpu);
689-
690-
cri->page = (void *)__get_free_page(GFP_KERNEL);
691-
if (!cri->page)
692-
goto err_page_alloc;
693-
636+
cri->page = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
694637
local_lock_init(&cri->lock);
695638
}
696-
697-
return 0;
698-
699-
err_page_alloc:
700-
while (cpu--)
701-
free_page((unsigned long)per_cpu_ptr(pcri, cpu)->page);
702-
return -ENOMEM;
703639
}
704640

705641
static int __init crypto_rng_init(void)
706642
{
707-
int ret;
708-
709643
if (!fips_enabled)
710644
return 0;
711645

712-
ret = alloc_pcpu_inst(&pcpu_default_rng);
713-
if (ret)
714-
return ret;
715-
716-
ret = alloc_pcpu_inst(&pcpu_reseed_rng);
717-
if (ret)
718-
goto free_pcpu_default;
719-
646+
/*
647+
* Never fail to register the RNG override in FIPS mode because failure
648+
* would result in the system quietly booting without the FIPS-mandated
649+
* RNG installed. This would be catastrophic for FIPS compliance, hence
650+
* the RNG override setup is *not* allowed to fail.
651+
*/
652+
alloc_pcpu_inst(&pcpu_default_rng);
653+
alloc_pcpu_inst(&pcpu_reseed_rng);
720654
random_register_extrng(&crypto_devrandom_rng);
721655
return 0;
722-
723-
free_pcpu_default:
724-
free_pcpu_inst(&pcpu_default_rng);
725-
return ret;
726656
}
727657

728658
late_initcall(crypto_rng_init);

0 commit comments

Comments
 (0)