diff options
| author | Fedor Pchelkin <pchelkin@ispras.ru> | 2026-08-31 10:58:09 +0300 |
|---|---|---|
| committer | Mika Westerberg <mika.westerberg@linux.intel.com> | 2026-09-02 09:07:46 +0200 |
| commit | 4310c6b8e75d6a47f7548e5948fbe6318aa4440a (patch) | |
| tree | 0032b584d8e218681a48126eb91f57091c351b83 /include/crypto/engine.h | |
| download | linux-stable-4310c6b8e75d6a47f7548e5948fbe6318aa4440a.tar.gz linux-stable-4310c6b8e75d6a47f7548e5948fbe6318aa4440a.zip | |
thunderbolt: Fix NULL dereference in tb_remove_work()grafted
There is a slight race between tb_remove_work() and tb_domain_remove()
which leads to dereferencing a NULL tb->root_switch pointer inside
tb_free_unplugged_xdomains():
Thread A Thread B
tb_remove_work()
tb_domain_remove()
mutex_lock(&tb->lock)
tb_stop()
/* doesn't cancel a running callback */
cancel_delayed_work(&tcm->remove_work)
...
tb_switch_remove(tb->root_switch)
tb->root_switch = NULL
mutex_unlock(&tb->lock)
mutex_lock(&tb->lock)
...
/* without checking ->root_switch */
tb_free_unplugged_xdomains(tb->root_switch)
mutex_unlock(&tb->lock)
Commit a8937f35cf39 ("thunderbolt: Remove XDomain from the bus without
holding tb->lock") doesn't seem right to move tb_free_unplugged_xdomains()
out of the &tb->lock section and the check for tb->root_switch, in
particular. It states:
For this reason separate removing the XDomain from the topology data
structures (where we need the lock) from unregistering the device from
the bus (where remove callbacks of the drivers are being called).
tb_free_unplugged_xdomains() belongs to the former group of functions
requiring the lock. And it also calls tb_xdomain_remove() which should
only be called with &tb->lock held.
Found by Linux Verification Center (linuxtesting.org) with Svace static
analysis tool.
Fixes: a8937f35cf39 ("thunderbolt: Remove XDomain from the bus without holding tb->lock")
Cc: stable@vger.kernel.org
Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Diffstat (limited to 'include/crypto/engine.h')
| -rw-r--r-- | include/crypto/engine.h | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/include/crypto/engine.h b/include/crypto/engine.h new file mode 100644 index 000000000..2e6034443 --- /dev/null +++ b/include/crypto/engine.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Crypto engine API + * + * Copyright (c) 2016 Baolin Wang <baolin.wang@linaro.org> + */ +#ifndef _CRYPTO_ENGINE_H +#define _CRYPTO_ENGINE_H + +#include <crypto/aead.h> +#include <crypto/akcipher.h> +#include <crypto/hash.h> +#include <crypto/kpp.h> +#include <crypto/skcipher.h> +#include <linux/types.h> + +struct crypto_engine; +struct device; + +/* + * struct crypto_engine_op - crypto hardware engine operations + * @do_one_request: do encryption for current request + */ +struct crypto_engine_op { + int (*do_one_request)(struct crypto_engine *engine, + void *areq); +}; + +struct aead_engine_alg { + struct aead_alg base; + struct crypto_engine_op op; +}; + +struct ahash_engine_alg { + struct ahash_alg base; + struct crypto_engine_op op; +}; + +struct akcipher_engine_alg { + struct akcipher_alg base; + struct crypto_engine_op op; +}; + +struct kpp_engine_alg { + struct kpp_alg base; + struct crypto_engine_op op; +}; + +struct skcipher_engine_alg { + struct skcipher_alg base; + struct crypto_engine_op op; +}; + +int crypto_transfer_aead_request_to_engine(struct crypto_engine *engine, + struct aead_request *req); +int crypto_transfer_akcipher_request_to_engine(struct crypto_engine *engine, + struct akcipher_request *req); +int crypto_transfer_hash_request_to_engine(struct crypto_engine *engine, + struct ahash_request *req); +int crypto_transfer_kpp_request_to_engine(struct crypto_engine *engine, + struct kpp_request *req); +int crypto_transfer_skcipher_request_to_engine(struct crypto_engine *engine, + struct skcipher_request *req); +void crypto_finalize_aead_request(struct crypto_engine *engine, + struct aead_request *req, int err); +void crypto_finalize_akcipher_request(struct crypto_engine *engine, + struct akcipher_request *req, int err); +void crypto_finalize_hash_request(struct crypto_engine *engine, + struct ahash_request *req, int err); +void crypto_finalize_kpp_request(struct crypto_engine *engine, + struct kpp_request *req, int err); +void crypto_finalize_skcipher_request(struct crypto_engine *engine, + struct skcipher_request *req, int err); +int crypto_engine_start(struct crypto_engine *engine); +int crypto_engine_stop(struct crypto_engine *engine); +struct crypto_engine *crypto_engine_alloc_init(struct device *dev, bool rt); +struct crypto_engine *crypto_engine_alloc_init_and_set(struct device *dev, + bool retry_support, + bool rt, int qlen); +void crypto_engine_exit(struct crypto_engine *engine); + +int crypto_engine_register_aead(struct aead_engine_alg *alg); +void crypto_engine_unregister_aead(struct aead_engine_alg *alg); +int crypto_engine_register_aeads(struct aead_engine_alg *algs, int count); +void crypto_engine_unregister_aeads(struct aead_engine_alg *algs, int count); + +int crypto_engine_register_ahash(struct ahash_engine_alg *alg); +void crypto_engine_unregister_ahash(struct ahash_engine_alg *alg); +int crypto_engine_register_ahashes(struct ahash_engine_alg *algs, int count); +void crypto_engine_unregister_ahashes(struct ahash_engine_alg *algs, + int count); + +int crypto_engine_register_akcipher(struct akcipher_engine_alg *alg); +void crypto_engine_unregister_akcipher(struct akcipher_engine_alg *alg); + +int crypto_engine_register_kpp(struct kpp_engine_alg *alg); +void crypto_engine_unregister_kpp(struct kpp_engine_alg *alg); + +int crypto_engine_register_skcipher(struct skcipher_engine_alg *alg); +void crypto_engine_unregister_skcipher(struct skcipher_engine_alg *alg); +int crypto_engine_register_skciphers(struct skcipher_engine_alg *algs, + int count); +void crypto_engine_unregister_skciphers(struct skcipher_engine_alg *algs, + int count); + +#endif /* _CRYPTO_ENGINE_H */ |
