Skip to content

Commit 44df536

Browse files
author
Rafael Aquini
committed
mm: zswap: move allocations during CPU init outside the lock
JIRA: https://issues.redhat.com/browse/RHEL-78678 CVE: CVE-2025-21693 Conflicts: * differences in the 2nd and 3rd hunks in this backport are due to RHEL9 missing upstream commits 6c303f1 ("crypto: introduce: acomp_is_async to expose if comp drivers might sleep") and 270700d ("mm/zswap: remove the memcpy if acomp is not sleepable"), which are not required for the sake of this work correctness. commit 779b995 Author: Yosry Ahmed <[email protected]> Date: Mon Jan 13 21:44:58 2025 +0000 mm: zswap: move allocations during CPU init outside the lock In zswap_cpu_comp_prepare(), allocations are made and assigned to various members of acomp_ctx under acomp_ctx->mutex. However, allocations may recurse into zswap through reclaim, trying to acquire the same mutex and deadlocking. Move the allocations before the mutex critical section. Only the initialization of acomp_ctx needs to be done with the mutex held. Link: https://lkml.kernel.org/r/[email protected] Fixes: 12dcb0e ("mm: zswap: properly synchronize freeing resources during CPU hotunplug") Signed-off-by: Yosry Ahmed <[email protected]> Reviewed-by: Chengming Zhou <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Nhat Pham <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Rafael Aquini <[email protected]>
1 parent c9b94ff commit 44df536

File tree

1 file changed

+23
-17
lines changed

1 file changed

+23
-17
lines changed

mm/zswap.c

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -710,36 +710,41 @@ static int zswap_cpu_comp_prepare(unsigned int cpu, struct hlist_node *node)
710710
{
711711
struct zswap_pool *pool = hlist_entry(node, struct zswap_pool, node);
712712
struct crypto_acomp_ctx *acomp_ctx = per_cpu_ptr(pool->acomp_ctx, cpu);
713-
struct crypto_acomp *acomp;
714-
struct acomp_req *req;
713+
struct crypto_acomp *acomp = NULL;
714+
struct acomp_req *req = NULL;
715+
u8 *buffer = NULL;
715716
int ret;
716717

717-
mutex_lock(&acomp_ctx->mutex);
718-
acomp_ctx->buffer = kmalloc_node(PAGE_SIZE * 2, GFP_KERNEL, cpu_to_node(cpu));
719-
if (!acomp_ctx->buffer) {
718+
buffer = kmalloc_node(PAGE_SIZE * 2, GFP_KERNEL, cpu_to_node(cpu));
719+
if (!buffer) {
720720
ret = -ENOMEM;
721-
goto buffer_fail;
721+
goto fail;
722722
}
723723

724724
acomp = crypto_alloc_acomp_node(pool->tfm_name, 0, 0, cpu_to_node(cpu));
725725
if (IS_ERR(acomp)) {
726726
pr_err("could not alloc crypto acomp %s : %ld\n",
727727
pool->tfm_name, PTR_ERR(acomp));
728728
ret = PTR_ERR(acomp);
729-
goto acomp_fail;
729+
goto fail;
730730
}
731-
acomp_ctx->acomp = acomp;
732731

733-
req = acomp_request_alloc(acomp_ctx->acomp);
732+
req = acomp_request_alloc(acomp);
734733
if (!req) {
735734
pr_err("could not alloc crypto acomp_request %s\n",
736735
pool->tfm_name);
737736
ret = -ENOMEM;
738-
goto req_fail;
737+
goto fail;
739738
}
740-
acomp_ctx->req = req;
741739

740+
/*
741+
* Only hold the mutex after completing allocations, otherwise we may
742+
* recurse into zswap through reclaim and attempt to hold the mutex
743+
* again resulting in a deadlock.
744+
*/
745+
mutex_lock(&acomp_ctx->mutex);
742746
crypto_init_wait(&acomp_ctx->wait);
747+
743748
/*
744749
* if the backend of acomp is async zip, crypto_req_done() will wakeup
745750
* crypto_wait_req(); if the backend of acomp is scomp, the callback
@@ -748,15 +753,16 @@ static int zswap_cpu_comp_prepare(unsigned int cpu, struct hlist_node *node)
748753
acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
749754
crypto_req_done, &acomp_ctx->wait);
750755

756+
acomp_ctx->buffer = buffer;
757+
acomp_ctx->acomp = acomp;
758+
acomp_ctx->req = req;
751759
mutex_unlock(&acomp_ctx->mutex);
752760
return 0;
753761

754-
req_fail:
755-
crypto_free_acomp(acomp_ctx->acomp);
756-
acomp_fail:
757-
kfree(acomp_ctx->buffer);
758-
buffer_fail:
759-
mutex_unlock(&acomp_ctx->mutex);
762+
fail:
763+
if (acomp)
764+
crypto_free_acomp(acomp);
765+
kfree(buffer);
760766
return ret;
761767
}
762768

0 commit comments

Comments
 (0)