crypto: qat - fix active_devs leak on crypto alg registration failure

adf_dev_start() registered both alg sets in a single condition.
If qat_algs_register() succeeds but qat_asym_algs_register() fails,
ADF_STATUS_CRYPTO_ALGS_REGISTERED is left clear, so adf_dev_stop() skips
qat_algs_unregister(): the skciphers and aeads stay registered with
active_devs stuck at 1, pinning the module.

Both helpers leak active_devs internally as well - they increment it and
return without decrementing when a crypto_register_*() call fails, and
the asym path also leaves the already-registered akcipher behind.

Split the registration in adf_dev_start() so that an asym failure
unregisters qat_algs, and unwind active_devs (and the akcipher) on the
error paths of both register helpers. While at it, propagate the error
code returned by the register helpers instead of a blanket -EFAULT.

Fixes: 9b2f33a1bf ("crypto: qat - fix unregistration of crypto algorithms")
Signed-off-by: Ahsan Atta <ahsan.atta@intel.com>
Reviewed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
Ahsan Atta 2026-09-09 15:15:21 +01:00 committed by Herbert Xu
parent 1e4d31c4eb
commit 178829f1b5
3 changed files with 45 additions and 20 deletions

View File

@ -260,13 +260,23 @@ static int adf_dev_start(struct adf_accel_dev *accel_dev)
clear_bit(ADF_STATUS_STARTING, &accel_dev->status);
set_bit(ADF_STATUS_STARTED, &accel_dev->status);
if (!list_empty(&accel_dev->crypto_list) &&
(qat_algs_register() || qat_asym_algs_register())) {
dev_err(&GET_DEV(accel_dev),
"Failed to register crypto algs\n");
set_bit(ADF_STATUS_STARTING, &accel_dev->status);
clear_bit(ADF_STATUS_STARTED, &accel_dev->status);
return -EFAULT;
if (!list_empty(&accel_dev->crypto_list)) {
ret = qat_algs_register();
if (ret) {
dev_err(&GET_DEV(accel_dev), "Failed to register crypto algs\n");
set_bit(ADF_STATUS_STARTING, &accel_dev->status);
clear_bit(ADF_STATUS_STARTED, &accel_dev->status);
return ret;
}
ret = qat_asym_algs_register();
if (ret) {
dev_err(&GET_DEV(accel_dev), "Failed to register crypto asym algs\n");
qat_algs_unregister();
set_bit(ADF_STATUS_STARTING, &accel_dev->status);
clear_bit(ADF_STATUS_STARTED, &accel_dev->status);
return ret;
}
}
set_bit(ADF_STATUS_CRYPTO_ALGS_REGISTERED, &accel_dev->status);

View File

@ -1319,19 +1319,22 @@ int qat_algs_register(void)
ret = crypto_register_skciphers(qat_skciphers,
ARRAY_SIZE(qat_skciphers));
if (ret)
goto unlock;
goto err_dec;
ret = crypto_register_aeads(qat_aeads, ARRAY_SIZE(qat_aeads));
if (ret)
goto unreg_algs;
goto err_unreg_skciphers;
mutex_unlock(&algs_lock);
return 0;
err_unreg_skciphers:
crypto_unregister_skciphers(qat_skciphers, ARRAY_SIZE(qat_skciphers));
err_dec:
active_devs--;
unlock:
mutex_unlock(&algs_lock);
return ret;
unreg_algs:
crypto_unregister_skciphers(qat_skciphers, ARRAY_SIZE(qat_skciphers));
goto unlock;
}
void qat_algs_unregister(void)

View File

@ -1340,13 +1340,25 @@ int qat_asym_algs_register(void)
int ret = 0;
mutex_lock(&algs_lock);
if (++active_devs == 1) {
rsa.base.cra_flags = 0;
ret = crypto_register_akcipher(&rsa);
if (ret)
goto unlock;
ret = crypto_register_kpp(&dh);
}
if (++active_devs != 1)
goto unlock;
rsa.base.cra_flags = 0;
ret = crypto_register_akcipher(&rsa);
if (ret)
goto err_dec;
ret = crypto_register_kpp(&dh);
if (ret)
goto err_unreg_akcipher;
mutex_unlock(&algs_lock);
return 0;
err_unreg_akcipher:
crypto_unregister_akcipher(&rsa);
err_dec:
active_devs--;
unlock:
mutex_unlock(&algs_lock);
return ret;