Commit dcc47a02 authored by Herbert Xu's avatar Herbert Xu
Browse files

crypto: null - Use spin lock instead of mutex



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: default avatar <syzbot+b3e02953598f447d4d2a@syzkaller.appspotmail.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 1047e21a
Loading
Loading
Loading
Loading
+26 −13
Original line number Diff line number Diff line
@@ -17,10 +17,10 @@
#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;
		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);