]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
crypto: null - Use spin lock instead of mutex
authorHerbert Xu <herbert@gondor.apana.org.au>
Wed, 12 Feb 2025 06:10:07 +0000 (14:10 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Sat, 22 Feb 2025 07:56:03 +0000 (15:56 +0800)
As the null algorithm may be freed in softirq context through
af_alg, use spin locks instead of mutexes to protect the default
null algorithm.

Reported-by: syzbot+b3e02953598f447d4d2a@syzkaller.appspotmail.com
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/crypto_null.c

index 5b84b0f7cc178fcd9499465add7ae0fcf7a8c75b..3378670286535a815dc3566b69cc65ffeb0aceff 100644 (file)
 #include <crypto/internal/skcipher.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/mm.h>
+#include <linux/spinlock.h>
 #include <linux/string.h>
 
-static DEFINE_MUTEX(crypto_default_null_skcipher_lock);
+static DEFINE_SPINLOCK(crypto_default_null_skcipher_lock);
 static struct crypto_sync_skcipher *crypto_default_null_skcipher;
 static int crypto_default_null_skcipher_refcnt;
 
@@ -152,23 +152,32 @@ MODULE_ALIAS_CRYPTO("cipher_null");
 
 struct crypto_sync_skcipher *crypto_get_default_null_skcipher(void)
 {
+       struct crypto_sync_skcipher *ntfm = NULL;
        struct crypto_sync_skcipher *tfm;
 
-       mutex_lock(&crypto_default_null_skcipher_lock);
+       spin_lock_bh(&crypto_default_null_skcipher_lock);
        tfm = crypto_default_null_skcipher;
 
        if (!tfm) {
-               tfm = crypto_alloc_sync_skcipher("ecb(cipher_null)", 0, 0);
-               if (IS_ERR(tfm))
-                       goto unlock;
-
-               crypto_default_null_skcipher = tfm;
+               spin_unlock_bh(&crypto_default_null_skcipher_lock);
+
+               ntfm = crypto_alloc_sync_skcipher("ecb(cipher_null)", 0, 0);
+               if (IS_ERR(ntfm))
+                       return ntfm;
+
+               spin_lock_bh(&crypto_default_null_skcipher_lock);
+               tfm = crypto_default_null_skcipher;
+               if (!tfm) {
+                       tfm = ntfm;
+                       ntfm = NULL;
+                       crypto_default_null_skcipher = tfm;
+               }
        }
 
        crypto_default_null_skcipher_refcnt++;
+       spin_unlock_bh(&crypto_default_null_skcipher_lock);
 
-unlock:
-       mutex_unlock(&crypto_default_null_skcipher_lock);
+       crypto_free_sync_skcipher(ntfm);
 
        return tfm;
 }
@@ -176,12 +185,16 @@ EXPORT_SYMBOL_GPL(crypto_get_default_null_skcipher);
 
 void crypto_put_default_null_skcipher(void)
 {
-       mutex_lock(&crypto_default_null_skcipher_lock);
+       struct crypto_sync_skcipher *tfm = NULL;
+
+       spin_lock_bh(&crypto_default_null_skcipher_lock);
        if (!--crypto_default_null_skcipher_refcnt) {
-               crypto_free_sync_skcipher(crypto_default_null_skcipher);
+               tfm = crypto_default_null_skcipher;
                crypto_default_null_skcipher = NULL;
        }
-       mutex_unlock(&crypto_default_null_skcipher_lock);
+       spin_unlock_bh(&crypto_default_null_skcipher_lock);
+
+       crypto_free_sync_skcipher(tfm);
 }
 EXPORT_SYMBOL_GPL(crypto_put_default_null_skcipher);