From b2a9364e29858f7f5251249b2cea473e3b5c47bf Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 3 Jul 2009 12:09:41 +0800 Subject: crypto: ansi_prng - Use just a BH lock The current code uses a mix of sping_lock() & spin_lock_irqsave(). This can lead to deadlock with the correct timming & cprng_get_random() + cprng_reset() sequence. I've converted them to bottom half locks since all three user grab just a BH lock so this runs probably in softirq :) Signed-off-by: Sebastian Andrzej Siewior Acked-by: Neil Horman Signed-off-by: Herbert Xu --- crypto/ansi_cprng.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'crypto/ansi_cprng.c') diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index d80ed4c1..ff00b58c 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -187,7 +187,6 @@ static int _get_more_prng_bytes(struct prng_context *ctx) /* Our exported functions */ static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx) { - unsigned long flags; unsigned char *ptr = buf; unsigned int byte_count = (unsigned int)nbytes; int err; @@ -196,7 +195,7 @@ static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx) if (nbytes < 0) return -EINVAL; - spin_lock_irqsave(&ctx->prng_lock, flags); + spin_lock_bh(&ctx->prng_lock); err = -EINVAL; if (ctx->flags & PRNG_NEED_RESET) @@ -268,7 +267,7 @@ empty_rbuf: goto remainder; done: - spin_unlock_irqrestore(&ctx->prng_lock, flags); + spin_unlock_bh(&ctx->prng_lock); dbgprint(KERN_CRIT "returning %d from get_prng_bytes in context %p\n", err, ctx); return err; @@ -287,7 +286,7 @@ static int reset_prng_context(struct prng_context *ctx, int rc = -EINVAL; unsigned char *prng_key; - spin_lock(&ctx->prng_lock); + spin_lock_bh(&ctx->prng_lock); ctx->flags |= PRNG_NEED_RESET; prng_key = (key != NULL) ? key : (unsigned char *)DEFAULT_PRNG_KEY; @@ -332,7 +331,7 @@ static int reset_prng_context(struct prng_context *ctx, rc = 0; ctx->flags &= ~PRNG_NEED_RESET; out: - spin_unlock(&ctx->prng_lock); + spin_unlock_bh(&ctx->prng_lock); return rc; -- cgit v1.2.3 From eb3bc74adaccd4e3d60e52ea1d6122f94b7c9818 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 3 Jul 2009 12:10:47 +0800 Subject: crypto: ansi_prng - alloc cipher just in init As reported by Eric Sesterhenn the re-allocation of the cipher in reset leads to: |BUG: sleeping function called from invalid context at kernel/rwsem.c:21 |in_atomic(): 1, irqs_disabled(): 0, pid: 4926, name: modprobe |INFO: lockdep is turned off. |Pid: 4926, comm: modprobe Tainted: G M 2.6.31-rc1-22297-g5298976 #24 |Call Trace: | [] __might_sleep+0xf9/0x101 | [] down_read+0x16/0x68 | [] crypto_alg_lookup+0x16/0x34 | [] crypto_larval_lookup+0x30/0xf9 | [] crypto_alg_mod_lookup+0x1d/0x62 | [] crypto_alloc_base+0x1e/0x64 | [] reset_prng_context+0xab/0x13f | [] ? __spin_lock_init+0x27/0x51 | [] cprng_init+0x2a/0x42 | [] __crypto_alloc_tfm+0xfa/0x128 | [] crypto_alloc_base+0x33/0x64 | [] alg_test_cprng+0x30/0x1f4 | [] alg_test+0x12f/0x19f | [] ? __alloc_pages_nodemask+0x14d/0x481 | [] do_test+0xf9d/0x163f [tcrypt] | [] do_test+0x3a1/0x163f [tcrypt] | [] tcrypt_mod_init+0x35/0x7c [tcrypt] | [] _stext+0x54/0x12c | [] ? tcrypt_mod_init+0x0/0x7c [tcrypt] | [] ? up_read+0x16/0x2b | [] ? __blocking_notifier_call_chain+0x40/0x4c | [] sys_init_module+0xa9/0x1bf | [] sysenter_do_call+0x12/0x32 because a spin lock is held and crypto_alloc_base() may sleep. There is no reason to re-allocate the cipher, the state is resetted in ->setkey(). This patches makes the cipher allocation a one time thing and moves it to init. Reported-by: Eric Sesterhenn Signed-off-by: Sebastian Andrzej Siewior Acked-by: Neil Horman Signed-off-by: Herbert Xu --- crypto/ansi_cprng.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) (limited to 'crypto/ansi_cprng.c') diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index ff00b58c..5357ba7d 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -283,7 +283,6 @@ static int reset_prng_context(struct prng_context *ctx, unsigned char *V, unsigned char *DT) { int ret; - int rc = -EINVAL; unsigned char *prng_key; spin_lock_bh(&ctx->prng_lock); @@ -307,34 +306,20 @@ static int reset_prng_context(struct prng_context *ctx, memset(ctx->rand_data, 0, DEFAULT_BLK_SZ); memset(ctx->last_rand_data, 0, DEFAULT_BLK_SZ); - if (ctx->tfm) - crypto_free_cipher(ctx->tfm); - - ctx->tfm = crypto_alloc_cipher("aes", 0, 0); - if (IS_ERR(ctx->tfm)) { - dbgprint(KERN_CRIT "Failed to alloc tfm for context %p\n", - ctx); - ctx->tfm = NULL; - goto out; - } - ctx->rand_data_valid = DEFAULT_BLK_SZ; ret = crypto_cipher_setkey(ctx->tfm, prng_key, klen); if (ret) { dbgprint(KERN_CRIT "PRNG: setkey() failed flags=%x\n", crypto_cipher_get_flags(ctx->tfm)); - crypto_free_cipher(ctx->tfm); goto out; } - rc = 0; + ret = 0; ctx->flags &= ~PRNG_NEED_RESET; out: spin_unlock_bh(&ctx->prng_lock); - - return rc; - + return ret; } static int cprng_init(struct crypto_tfm *tfm) @@ -342,6 +327,12 @@ static int cprng_init(struct crypto_tfm *tfm) struct prng_context *ctx = crypto_tfm_ctx(tfm); spin_lock_init(&ctx->prng_lock); + ctx->tfm = crypto_alloc_cipher("aes", 0, 0); + if (IS_ERR(ctx->tfm)) { + dbgprint(KERN_CRIT "Failed to alloc tfm for context %p\n", + ctx); + return PTR_ERR(ctx->tfm); + } if (reset_prng_context(ctx, NULL, DEFAULT_PRNG_KSZ, NULL, NULL) < 0) return -EINVAL; -- cgit v1.2.3 From 005ba80d9b2c6a679993944b2aacb72ac03490dd Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Sat, 29 Aug 2009 17:36:25 +1000 Subject: crypto: ansi_cprng - Fix module initialization Return the value we got from crypto_register_alg() instead of returning 0 in any case. Signed-off-by: Steffen Klassert Acked-by: Neil Horman Signed-off-by: Herbert Xu --- crypto/ansi_cprng.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'crypto/ansi_cprng.c') diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index 5357ba7d..3aa6e383 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -408,17 +408,10 @@ static struct crypto_alg rng_alg = { /* Module initalization */ static int __init prng_mod_init(void) { - int ret = 0; - if (fips_enabled) rng_alg.cra_priority += 200; - ret = crypto_register_alg(&rng_alg); - - if (ret) - goto out; -out: - return 0; + return crypto_register_alg(&rng_alg); } static void __exit prng_mod_fini(void) -- cgit v1.2.3