2017-12-21 11:35:30 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2010-01-06 08:47:10 +00:00
|
|
|
/*
|
|
|
|
* padata.c - generic interface to process data streams in parallel
|
|
|
|
*
|
2019-12-03 19:31:14 +00:00
|
|
|
* See Documentation/core-api/padata.rst for more information.
|
2012-03-28 06:42:34 +00:00
|
|
|
*
|
2010-01-06 08:47:10 +00:00
|
|
|
* Copyright (C) 2008, 2009 secunet Security Networks AG
|
|
|
|
* Copyright (C) 2008, 2009 Steffen Klassert <steffen.klassert@secunet.com>
|
|
|
|
*
|
2020-06-03 22:59:43 +00:00
|
|
|
* Copyright (c) 2020 Oracle and/or its affiliates.
|
|
|
|
* Author: Daniel Jordan <daniel.m.jordan@oracle.com>
|
2010-01-06 08:47:10 +00:00
|
|
|
*/
|
|
|
|
|
2020-06-03 22:59:43 +00:00
|
|
|
#include <linux/completion.h>
|
2011-05-23 18:51:41 +00:00
|
|
|
#include <linux/export.h>
|
2010-01-06 08:47:10 +00:00
|
|
|
#include <linux/cpumask.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
#include <linux/cpu.h>
|
|
|
|
#include <linux/padata.h>
|
|
|
|
#include <linux/mutex.h>
|
|
|
|
#include <linux/sched.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2010-07-14 10:33:08 +00:00
|
|
|
#include <linux/sysfs.h>
|
2010-01-06 08:47:10 +00:00
|
|
|
#include <linux/rcupdate.h>
|
|
|
|
|
2020-06-03 22:59:43 +00:00
|
|
|
#define PADATA_WORK_ONSTACK 1 /* Work's memory is on stack */
|
|
|
|
|
2020-06-03 22:59:39 +00:00
|
|
|
struct padata_work {
|
|
|
|
struct work_struct pw_work;
|
|
|
|
struct list_head pw_list; /* padata_free_works linkage */
|
|
|
|
void *pw_data;
|
|
|
|
};
|
|
|
|
|
|
|
|
static DEFINE_SPINLOCK(padata_works_lock);
|
|
|
|
static struct padata_work *padata_works;
|
|
|
|
static LIST_HEAD(padata_free_works);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-06-03 22:59:43 +00:00
|
|
|
struct padata_mt_job_state {
|
|
|
|
spinlock_t lock;
|
|
|
|
struct completion completion;
|
|
|
|
struct padata_mt_job *job;
|
|
|
|
int nworks;
|
|
|
|
int nworks_fini;
|
|
|
|
unsigned long chunk_size;
|
|
|
|
};
|
|
|
|
|
2019-11-19 05:17:31 +00:00
|
|
|
static void padata_free_pd(struct parallel_data *pd);
|
2020-06-03 22:59:43 +00:00
|
|
|
static void __init padata_mt_helper(struct work_struct *work);
|
2019-11-19 05:17:31 +00:00
|
|
|
|
2010-01-06 08:47:10 +00:00
|
|
|
static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index)
|
|
|
|
{
|
|
|
|
int cpu, target_cpu;
|
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
target_cpu = cpumask_first(pd->cpumask.pcpu);
|
2010-01-06 08:47:10 +00:00
|
|
|
for (cpu = 0; cpu < cpu_index; cpu++)
|
2010-07-14 10:31:57 +00:00
|
|
|
target_cpu = cpumask_next(target_cpu, pd->cpumask.pcpu);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
|
|
|
return target_cpu;
|
|
|
|
}
|
|
|
|
|
2019-09-06 01:40:28 +00:00
|
|
|
static int padata_cpu_hash(struct parallel_data *pd, unsigned int seq_nr)
|
2010-01-06 08:47:10 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Hash the sequence numbers to the cpus by taking
|
|
|
|
* seq_nr mod. number of cpus in use.
|
|
|
|
*/
|
2019-09-06 01:40:28 +00:00
|
|
|
int cpu_index = seq_nr % cpumask_weight(pd->cpumask.pcpu);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
|
|
|
return padata_index_to_cpu(pd, cpu_index);
|
|
|
|
}
|
|
|
|
|
2020-06-03 22:59:39 +00:00
|
|
|
static struct padata_work *padata_work_alloc(void)
|
2010-01-06 08:47:10 +00:00
|
|
|
{
|
2020-06-03 22:59:39 +00:00
|
|
|
struct padata_work *pw;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-06-03 22:59:39 +00:00
|
|
|
lockdep_assert_held(&padata_works_lock);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-06-03 22:59:39 +00:00
|
|
|
if (list_empty(&padata_free_works))
|
|
|
|
return NULL; /* No more work items allowed to be queued. */
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-06-03 22:59:39 +00:00
|
|
|
pw = list_first_entry(&padata_free_works, struct padata_work, pw_list);
|
|
|
|
list_del(&pw->pw_list);
|
|
|
|
return pw;
|
|
|
|
}
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2022-12-13 18:35:28 +00:00
|
|
|
/*
|
|
|
|
* This function is marked __ref because this function may be optimized in such
|
|
|
|
* a way that it directly refers to work_fn's address, which causes modpost to
|
|
|
|
* complain when work_fn is marked __init. This scenario was observed with clang
|
|
|
|
* LTO, where padata_work_init() was optimized to refer directly to
|
|
|
|
* padata_mt_helper() because the calls to padata_work_init() with other work_fn
|
|
|
|
* values were eliminated or inlined.
|
|
|
|
*/
|
|
|
|
static void __ref padata_work_init(struct padata_work *pw, work_func_t work_fn,
|
|
|
|
void *data, int flags)
|
2020-06-03 22:59:39 +00:00
|
|
|
{
|
2020-06-03 22:59:43 +00:00
|
|
|
if (flags & PADATA_WORK_ONSTACK)
|
|
|
|
INIT_WORK_ONSTACK(&pw->pw_work, work_fn);
|
|
|
|
else
|
|
|
|
INIT_WORK(&pw->pw_work, work_fn);
|
2020-06-03 22:59:39 +00:00
|
|
|
pw->pw_data = data;
|
|
|
|
}
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-06-03 22:59:43 +00:00
|
|
|
static int __init padata_work_alloc_mt(int nworks, void *data,
|
|
|
|
struct list_head *head)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2024-04-03 09:36:18 +00:00
|
|
|
spin_lock_bh(&padata_works_lock);
|
2020-06-03 22:59:43 +00:00
|
|
|
/* Start at 1 because the current task participates in the job. */
|
|
|
|
for (i = 1; i < nworks; ++i) {
|
|
|
|
struct padata_work *pw = padata_work_alloc();
|
|
|
|
|
|
|
|
if (!pw)
|
|
|
|
break;
|
|
|
|
padata_work_init(pw, padata_mt_helper, data, 0);
|
|
|
|
list_add(&pw->pw_list, head);
|
|
|
|
}
|
2024-04-03 09:36:18 +00:00
|
|
|
spin_unlock_bh(&padata_works_lock);
|
2020-06-03 22:59:43 +00:00
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2020-06-03 22:59:39 +00:00
|
|
|
static void padata_work_free(struct padata_work *pw)
|
|
|
|
{
|
|
|
|
lockdep_assert_held(&padata_works_lock);
|
|
|
|
list_add(&pw->pw_list, &padata_free_works);
|
|
|
|
}
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-06-03 22:59:43 +00:00
|
|
|
static void __init padata_works_free(struct list_head *works)
|
|
|
|
{
|
|
|
|
struct padata_work *cur, *next;
|
|
|
|
|
|
|
|
if (list_empty(works))
|
|
|
|
return;
|
|
|
|
|
2024-04-03 09:36:18 +00:00
|
|
|
spin_lock_bh(&padata_works_lock);
|
2020-06-03 22:59:43 +00:00
|
|
|
list_for_each_entry_safe(cur, next, works, pw_list) {
|
|
|
|
list_del(&cur->pw_list);
|
|
|
|
padata_work_free(cur);
|
|
|
|
}
|
2024-04-03 09:36:18 +00:00
|
|
|
spin_unlock_bh(&padata_works_lock);
|
2020-06-03 22:59:43 +00:00
|
|
|
}
|
|
|
|
|
2020-06-03 22:59:39 +00:00
|
|
|
static void padata_parallel_worker(struct work_struct *parallel_work)
|
|
|
|
{
|
|
|
|
struct padata_work *pw = container_of(parallel_work, struct padata_work,
|
|
|
|
pw_work);
|
|
|
|
struct padata_priv *padata = pw->pw_data;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-06-03 22:59:39 +00:00
|
|
|
local_bh_disable();
|
|
|
|
padata->parallel(padata);
|
|
|
|
spin_lock(&padata_works_lock);
|
|
|
|
padata_work_free(pw);
|
|
|
|
spin_unlock(&padata_works_lock);
|
2010-01-06 08:47:10 +00:00
|
|
|
local_bh_enable();
|
|
|
|
}
|
|
|
|
|
2010-05-19 03:44:27 +00:00
|
|
|
/**
|
2010-01-06 08:47:10 +00:00
|
|
|
* padata_do_parallel - padata parallelization function
|
|
|
|
*
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
* @ps: padatashell
|
2010-01-06 08:47:10 +00:00
|
|
|
* @padata: object to be parallelized
|
2019-09-06 01:40:24 +00:00
|
|
|
* @cb_cpu: pointer to the CPU that the serialization callback function should
|
|
|
|
* run on. If it's not in the serial cpumask of @pinst
|
|
|
|
* (i.e. cpumask.cbcpu), this function selects a fallback CPU and if
|
|
|
|
* none found, returns -EINVAL.
|
2010-01-06 08:47:10 +00:00
|
|
|
*
|
|
|
|
* The parallelization callback function will run with BHs off.
|
|
|
|
* Note: Every object which is parallelized by padata_do_parallel
|
|
|
|
* must be seen by padata_do_serial.
|
2019-12-03 19:31:14 +00:00
|
|
|
*
|
|
|
|
* Return: 0 on success or else negative error code.
|
2010-01-06 08:47:10 +00:00
|
|
|
*/
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
int padata_do_parallel(struct padata_shell *ps,
|
2019-09-06 01:40:24 +00:00
|
|
|
struct padata_priv *padata, int *cb_cpu)
|
2010-01-06 08:47:10 +00:00
|
|
|
{
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
struct padata_instance *pinst = ps->pinst;
|
2020-06-03 22:59:39 +00:00
|
|
|
int i, cpu, cpu_index, err;
|
2010-01-06 08:47:10 +00:00
|
|
|
struct parallel_data *pd;
|
2020-06-03 22:59:39 +00:00
|
|
|
struct padata_work *pw;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
|
|
|
rcu_read_lock_bh();
|
|
|
|
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
pd = rcu_dereference_bh(ps->pd);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2010-07-07 13:32:02 +00:00
|
|
|
err = -EINVAL;
|
2010-07-20 06:51:25 +00:00
|
|
|
if (!(pinst->flags & PADATA_INIT) || pinst->flags & PADATA_INVALID)
|
2010-01-06 08:47:10 +00:00
|
|
|
goto out;
|
|
|
|
|
2019-09-06 01:40:24 +00:00
|
|
|
if (!cpumask_test_cpu(*cb_cpu, pd->cpumask.cbcpu)) {
|
2022-01-23 18:38:52 +00:00
|
|
|
if (cpumask_empty(pd->cpumask.cbcpu))
|
2019-09-06 01:40:24 +00:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* Select an alternate fallback CPU and notify the caller. */
|
|
|
|
cpu_index = *cb_cpu % cpumask_weight(pd->cpumask.cbcpu);
|
|
|
|
|
|
|
|
cpu = cpumask_first(pd->cpumask.cbcpu);
|
|
|
|
for (i = 0; i < cpu_index; i++)
|
|
|
|
cpu = cpumask_next(cpu, pd->cpumask.cbcpu);
|
|
|
|
|
|
|
|
*cb_cpu = cpu;
|
|
|
|
}
|
2010-01-06 08:47:10 +00:00
|
|
|
|
crypto: pcrypt - Fix hungtask for PADATA_RESET
We found a hungtask bug in test_aead_vec_cfg as follows:
INFO: task cryptomgr_test:391009 blocked for more than 120 seconds.
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
Call trace:
__switch_to+0x98/0xe0
__schedule+0x6c4/0xf40
schedule+0xd8/0x1b4
schedule_timeout+0x474/0x560
wait_for_common+0x368/0x4e0
wait_for_completion+0x20/0x30
wait_for_completion+0x20/0x30
test_aead_vec_cfg+0xab4/0xd50
test_aead+0x144/0x1f0
alg_test_aead+0xd8/0x1e0
alg_test+0x634/0x890
cryptomgr_test+0x40/0x70
kthread+0x1e0/0x220
ret_from_fork+0x10/0x18
Kernel panic - not syncing: hung_task: blocked tasks
For padata_do_parallel, when the return err is 0 or -EBUSY, it will call
wait_for_completion(&wait->completion) in test_aead_vec_cfg. In normal
case, aead_request_complete() will be called in pcrypt_aead_serial and the
return err is 0 for padata_do_parallel. But, when pinst->flags is
PADATA_RESET, the return err is -EBUSY for padata_do_parallel, and it
won't call aead_request_complete(). Therefore, test_aead_vec_cfg will
hung at wait_for_completion(&wait->completion), which will cause
hungtask.
The problem comes as following:
(padata_do_parallel) |
rcu_read_lock_bh(); |
err = -EINVAL; | (padata_replace)
| pinst->flags |= PADATA_RESET;
err = -EBUSY |
if (pinst->flags & PADATA_RESET) |
rcu_read_unlock_bh() |
return err
In order to resolve the problem, we replace the return err -EBUSY with
-EAGAIN, which means parallel_data is changing, and the caller should call
it again.
v3:
remove retry and just change the return err.
v2:
introduce padata_try_do_parallel() in pcrypt_aead_encrypt and
pcrypt_aead_decrypt to solve the hungtask.
Signed-off-by: Lu Jialin <lujialin4@huawei.com>
Signed-off-by: Guo Zihua <guozihua@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2023-09-04 13:33:41 +00:00
|
|
|
err = -EBUSY;
|
2010-01-06 08:47:10 +00:00
|
|
|
if ((pinst->flags & PADATA_RESET))
|
|
|
|
goto out;
|
|
|
|
|
2021-07-20 15:05:11 +00:00
|
|
|
refcount_inc(&pd->refcnt);
|
2010-01-06 08:47:10 +00:00
|
|
|
padata->pd = pd;
|
2019-09-06 01:40:24 +00:00
|
|
|
padata->cb_cpu = *cb_cpu;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-06-03 22:59:39 +00:00
|
|
|
spin_lock(&padata_works_lock);
|
|
|
|
padata->seq_nr = ++pd->seq_nr;
|
|
|
|
pw = padata_work_alloc();
|
|
|
|
spin_unlock(&padata_works_lock);
|
2020-09-02 17:07:56 +00:00
|
|
|
|
2022-11-17 01:28:02 +00:00
|
|
|
if (!pw) {
|
|
|
|
/* Maximum works limit exceeded, run in the current task. */
|
|
|
|
padata->parallel(padata);
|
|
|
|
}
|
|
|
|
|
2020-09-02 17:07:56 +00:00
|
|
|
rcu_read_unlock_bh();
|
|
|
|
|
2020-06-03 22:59:39 +00:00
|
|
|
if (pw) {
|
2020-06-03 22:59:43 +00:00
|
|
|
padata_work_init(pw, padata_parallel_worker, padata, 0);
|
2020-06-03 22:59:39 +00:00
|
|
|
queue_work(pinst->parallel_wq, &pw->pw_work);
|
|
|
|
}
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-06-03 22:59:39 +00:00
|
|
|
return 0;
|
2010-01-06 08:47:10 +00:00
|
|
|
out:
|
|
|
|
rcu_read_unlock_bh();
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(padata_do_parallel);
|
|
|
|
|
2010-05-19 03:44:27 +00:00
|
|
|
/*
|
2019-09-06 01:40:28 +00:00
|
|
|
* padata_find_next - Find the next object that needs serialization.
|
2010-05-19 03:44:27 +00:00
|
|
|
*
|
2019-12-03 19:31:14 +00:00
|
|
|
* Return:
|
|
|
|
* * A pointer to the control struct of the next object that needs
|
|
|
|
* serialization, if present in one of the percpu reorder queues.
|
|
|
|
* * NULL, if the next object that needs serialization will
|
|
|
|
* be parallel processed by another cpu and is not yet present in
|
|
|
|
* the cpu's reorder queue.
|
2010-05-19 03:44:27 +00:00
|
|
|
*/
|
2019-09-06 01:40:28 +00:00
|
|
|
static struct padata_priv *padata_find_next(struct parallel_data *pd,
|
|
|
|
bool remove_object)
|
2010-01-06 08:47:10 +00:00
|
|
|
{
|
|
|
|
struct padata_priv *padata;
|
|
|
|
struct padata_list *reorder;
|
2019-07-18 15:01:46 +00:00
|
|
|
int cpu = pd->cpu;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-07-14 20:13:56 +00:00
|
|
|
reorder = per_cpu_ptr(pd->reorder_list, cpu);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
padata: avoid race in reordering
Under extremely heavy uses of padata, crashes occur, and with list
debugging turned on, this happens instead:
[87487.298728] WARNING: CPU: 1 PID: 882 at lib/list_debug.c:33
__list_add+0xae/0x130
[87487.301868] list_add corruption. prev->next should be next
(ffffb17abfc043d0), but was ffff8dba70872c80. (prev=ffff8dba70872b00).
[87487.339011] [<ffffffff9a53d075>] dump_stack+0x68/0xa3
[87487.342198] [<ffffffff99e119a1>] ? console_unlock+0x281/0x6d0
[87487.345364] [<ffffffff99d6b91f>] __warn+0xff/0x140
[87487.348513] [<ffffffff99d6b9aa>] warn_slowpath_fmt+0x4a/0x50
[87487.351659] [<ffffffff9a58b5de>] __list_add+0xae/0x130
[87487.354772] [<ffffffff9add5094>] ? _raw_spin_lock+0x64/0x70
[87487.357915] [<ffffffff99eefd66>] padata_reorder+0x1e6/0x420
[87487.361084] [<ffffffff99ef0055>] padata_do_serial+0xa5/0x120
padata_reorder calls list_add_tail with the list to which its adding
locked, which seems correct:
spin_lock(&squeue->serial.lock);
list_add_tail(&padata->list, &squeue->serial.list);
spin_unlock(&squeue->serial.lock);
This therefore leaves only place where such inconsistency could occur:
if padata->list is added at the same time on two different threads.
This pdata pointer comes from the function call to
padata_get_next(pd), which has in it the following block:
next_queue = per_cpu_ptr(pd->pqueue, cpu);
padata = NULL;
reorder = &next_queue->reorder;
if (!list_empty(&reorder->list)) {
padata = list_entry(reorder->list.next,
struct padata_priv, list);
spin_lock(&reorder->lock);
list_del_init(&padata->list);
atomic_dec(&pd->reorder_objects);
spin_unlock(&reorder->lock);
pd->processed++;
goto out;
}
out:
return padata;
I strongly suspect that the problem here is that two threads can race
on reorder list. Even though the deletion is locked, call to
list_entry is not locked, which means it's feasible that two threads
pick up the same padata object and subsequently call list_add_tail on
them at the same time. The fix is thus be hoist that lock outside of
that block.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Acked-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2017-03-23 11:24:43 +00:00
|
|
|
spin_lock(&reorder->lock);
|
2019-09-06 01:40:28 +00:00
|
|
|
if (list_empty(&reorder->list)) {
|
|
|
|
spin_unlock(&reorder->lock);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2019-09-06 01:40:28 +00:00
|
|
|
padata = list_entry(reorder->list.next, struct padata_priv, list);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2019-09-06 01:40:28 +00:00
|
|
|
/*
|
|
|
|
* Checks the rare case where two or more parallel jobs have hashed to
|
|
|
|
* the same CPU and one of the later ones finishes first.
|
|
|
|
*/
|
|
|
|
if (padata->seq_nr != pd->processed) {
|
padata: avoid race in reordering
Under extremely heavy uses of padata, crashes occur, and with list
debugging turned on, this happens instead:
[87487.298728] WARNING: CPU: 1 PID: 882 at lib/list_debug.c:33
__list_add+0xae/0x130
[87487.301868] list_add corruption. prev->next should be next
(ffffb17abfc043d0), but was ffff8dba70872c80. (prev=ffff8dba70872b00).
[87487.339011] [<ffffffff9a53d075>] dump_stack+0x68/0xa3
[87487.342198] [<ffffffff99e119a1>] ? console_unlock+0x281/0x6d0
[87487.345364] [<ffffffff99d6b91f>] __warn+0xff/0x140
[87487.348513] [<ffffffff99d6b9aa>] warn_slowpath_fmt+0x4a/0x50
[87487.351659] [<ffffffff9a58b5de>] __list_add+0xae/0x130
[87487.354772] [<ffffffff9add5094>] ? _raw_spin_lock+0x64/0x70
[87487.357915] [<ffffffff99eefd66>] padata_reorder+0x1e6/0x420
[87487.361084] [<ffffffff99ef0055>] padata_do_serial+0xa5/0x120
padata_reorder calls list_add_tail with the list to which its adding
locked, which seems correct:
spin_lock(&squeue->serial.lock);
list_add_tail(&padata->list, &squeue->serial.list);
spin_unlock(&squeue->serial.lock);
This therefore leaves only place where such inconsistency could occur:
if padata->list is added at the same time on two different threads.
This pdata pointer comes from the function call to
padata_get_next(pd), which has in it the following block:
next_queue = per_cpu_ptr(pd->pqueue, cpu);
padata = NULL;
reorder = &next_queue->reorder;
if (!list_empty(&reorder->list)) {
padata = list_entry(reorder->list.next,
struct padata_priv, list);
spin_lock(&reorder->lock);
list_del_init(&padata->list);
atomic_dec(&pd->reorder_objects);
spin_unlock(&reorder->lock);
pd->processed++;
goto out;
}
out:
return padata;
I strongly suspect that the problem here is that two threads can race
on reorder list. Even though the deletion is locked, call to
list_entry is not locked, which means it's feasible that two threads
pick up the same padata object and subsequently call list_add_tail on
them at the same time. The fix is thus be hoist that lock outside of
that block.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Acked-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2017-03-23 11:24:43 +00:00
|
|
|
spin_unlock(&reorder->lock);
|
2019-09-06 01:40:28 +00:00
|
|
|
return NULL;
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
|
2019-09-06 01:40:28 +00:00
|
|
|
if (remove_object) {
|
|
|
|
list_del_init(&padata->list);
|
|
|
|
++pd->processed;
|
|
|
|
pd->cpu = cpumask_next_wrap(cpu, pd->cpumask.pcpu, -1, false);
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
|
2019-09-06 01:40:28 +00:00
|
|
|
spin_unlock(&reorder->lock);
|
2010-01-06 08:47:10 +00:00
|
|
|
return padata;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void padata_reorder(struct parallel_data *pd)
|
|
|
|
{
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
struct padata_instance *pinst = pd->ps->pinst;
|
2012-03-09 06:20:12 +00:00
|
|
|
int cb_cpu;
|
2010-01-06 08:47:10 +00:00
|
|
|
struct padata_priv *padata;
|
2010-07-14 10:31:57 +00:00
|
|
|
struct padata_serial_queue *squeue;
|
2020-07-14 20:13:56 +00:00
|
|
|
struct padata_list *reorder;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2010-05-19 03:44:27 +00:00
|
|
|
/*
|
|
|
|
* We need to ensure that only one cpu can work on dequeueing of
|
|
|
|
* the reorder queue the time. Calculating in which percpu reorder
|
|
|
|
* queue the next object will arrive takes some time. A spinlock
|
|
|
|
* would be highly contended. Also it is not clear in which order
|
|
|
|
* the objects arrive to the reorder queues. So a cpu could wait to
|
|
|
|
* get the lock just to notice that there is nothing to do at the
|
|
|
|
* moment. Therefore we use a trylock and let the holder of the lock
|
|
|
|
* care for all the objects enqueued during the holdtime of the lock.
|
|
|
|
*/
|
2010-01-06 08:47:10 +00:00
|
|
|
if (!spin_trylock_bh(&pd->lock))
|
2010-05-19 03:43:14 +00:00
|
|
|
return;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
|
|
|
while (1) {
|
2019-09-06 01:40:28 +00:00
|
|
|
padata = padata_find_next(pd, true);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2010-05-19 03:44:27 +00:00
|
|
|
/*
|
2017-04-12 08:40:19 +00:00
|
|
|
* If the next object that needs serialization is parallel
|
|
|
|
* processed by another cpu and is still on it's way to the
|
|
|
|
* cpu's reorder queue, nothing to do for now.
|
2010-05-19 03:44:27 +00:00
|
|
|
*/
|
2019-09-06 01:40:28 +00:00
|
|
|
if (!padata)
|
2010-01-06 08:47:10 +00:00
|
|
|
break;
|
|
|
|
|
2012-03-09 06:20:12 +00:00
|
|
|
cb_cpu = padata->cb_cpu;
|
|
|
|
squeue = per_cpu_ptr(pd->squeue, cb_cpu);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
spin_lock(&squeue->serial.lock);
|
|
|
|
list_add_tail(&padata->list, &squeue->serial.list);
|
|
|
|
spin_unlock(&squeue->serial.lock);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2019-09-06 01:40:27 +00:00
|
|
|
queue_work_on(cb_cpu, pinst->serial_wq, &squeue->work);
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
spin_unlock_bh(&pd->lock);
|
|
|
|
|
2010-05-19 03:44:27 +00:00
|
|
|
/*
|
|
|
|
* The next object that needs serialization might have arrived to
|
2019-07-18 15:01:46 +00:00
|
|
|
* the reorder queues in the meantime.
|
2019-07-16 16:32:53 +00:00
|
|
|
*
|
2019-07-18 15:01:46 +00:00
|
|
|
* Ensure reorder queue is read after pd->lock is dropped so we see
|
|
|
|
* new objects from another task in padata_do_serial. Pairs with
|
2020-06-08 21:26:52 +00:00
|
|
|
* smp_mb in padata_do_serial.
|
2010-05-19 03:44:27 +00:00
|
|
|
*/
|
2019-07-16 16:32:53 +00:00
|
|
|
smp_mb();
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-07-14 20:13:56 +00:00
|
|
|
reorder = per_cpu_ptr(pd->reorder_list, pd->cpu);
|
|
|
|
if (!list_empty(&reorder->list) && padata_find_next(pd, false))
|
2019-09-06 01:40:27 +00:00
|
|
|
queue_work(pinst->serial_wq, &pd->reorder_work);
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
|
2017-09-08 18:57:10 +00:00
|
|
|
static void invoke_padata_reorder(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct parallel_data *pd;
|
|
|
|
|
|
|
|
local_bh_disable();
|
2019-07-18 15:01:46 +00:00
|
|
|
pd = container_of(work, struct parallel_data, reorder_work);
|
2017-09-08 18:57:10 +00:00
|
|
|
padata_reorder(pd);
|
|
|
|
local_bh_enable();
|
|
|
|
}
|
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
static void padata_serial_worker(struct work_struct *serial_work)
|
2010-01-06 08:47:10 +00:00
|
|
|
{
|
2010-07-14 10:31:57 +00:00
|
|
|
struct padata_serial_queue *squeue;
|
2010-01-06 08:47:10 +00:00
|
|
|
struct parallel_data *pd;
|
|
|
|
LIST_HEAD(local_list);
|
2019-11-19 05:17:31 +00:00
|
|
|
int cnt;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
|
|
|
local_bh_disable();
|
2010-07-14 10:31:57 +00:00
|
|
|
squeue = container_of(serial_work, struct padata_serial_queue, work);
|
|
|
|
pd = squeue->pd;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
spin_lock(&squeue->serial.lock);
|
|
|
|
list_replace_init(&squeue->serial.list, &local_list);
|
|
|
|
spin_unlock(&squeue->serial.lock);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2019-11-19 05:17:31 +00:00
|
|
|
cnt = 0;
|
|
|
|
|
2010-01-06 08:47:10 +00:00
|
|
|
while (!list_empty(&local_list)) {
|
|
|
|
struct padata_priv *padata;
|
|
|
|
|
|
|
|
padata = list_entry(local_list.next,
|
|
|
|
struct padata_priv, list);
|
|
|
|
|
|
|
|
list_del_init(&padata->list);
|
|
|
|
|
|
|
|
padata->serial(padata);
|
2019-11-19 05:17:31 +00:00
|
|
|
cnt++;
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
local_bh_enable();
|
2019-11-19 05:17:31 +00:00
|
|
|
|
2021-07-20 15:05:11 +00:00
|
|
|
if (refcount_sub_and_test(cnt, &pd->refcnt))
|
2019-11-19 05:17:31 +00:00
|
|
|
padata_free_pd(pd);
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
|
2010-05-19 03:44:27 +00:00
|
|
|
/**
|
2010-01-06 08:47:10 +00:00
|
|
|
* padata_do_serial - padata serialization function
|
|
|
|
*
|
|
|
|
* @padata: object to be serialized.
|
|
|
|
*
|
|
|
|
* padata_do_serial must be called for every parallelized object.
|
|
|
|
* The serialization callback function will run with BHs off.
|
|
|
|
*/
|
|
|
|
void padata_do_serial(struct padata_priv *padata)
|
|
|
|
{
|
2019-07-19 19:04:44 +00:00
|
|
|
struct parallel_data *pd = padata->pd;
|
2020-06-03 22:59:39 +00:00
|
|
|
int hashed_cpu = padata_cpu_hash(pd, padata->seq_nr);
|
2020-07-14 20:13:56 +00:00
|
|
|
struct padata_list *reorder = per_cpu_ptr(pd->reorder_list, hashed_cpu);
|
2019-09-06 01:40:28 +00:00
|
|
|
struct padata_priv *cur;
|
2022-11-17 01:28:04 +00:00
|
|
|
struct list_head *pos;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-07-14 20:13:56 +00:00
|
|
|
spin_lock(&reorder->lock);
|
2019-09-06 01:40:28 +00:00
|
|
|
/* Sort in ascending order of sequence number. */
|
2022-11-17 01:28:04 +00:00
|
|
|
list_for_each_prev(pos, &reorder->list) {
|
|
|
|
cur = list_entry(pos, struct padata_priv, list);
|
2024-08-09 06:21:42 +00:00
|
|
|
/* Compare by difference to consider integer wrap around */
|
|
|
|
if ((signed int)(cur->seq_nr - padata->seq_nr) < 0)
|
2019-09-06 01:40:28 +00:00
|
|
|
break;
|
2022-11-17 01:28:04 +00:00
|
|
|
}
|
|
|
|
list_add(&padata->list, pos);
|
2020-07-14 20:13:56 +00:00
|
|
|
spin_unlock(&reorder->lock);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2019-07-16 16:32:53 +00:00
|
|
|
/*
|
2019-07-18 15:01:46 +00:00
|
|
|
* Ensure the addition to the reorder list is ordered correctly
|
2019-07-16 16:32:53 +00:00
|
|
|
* with the trylock of pd->lock in padata_reorder. Pairs with smp_mb
|
|
|
|
* in padata_reorder.
|
|
|
|
*/
|
2020-06-08 21:26:52 +00:00
|
|
|
smp_mb();
|
2019-07-16 16:32:53 +00:00
|
|
|
|
2019-07-18 15:01:46 +00:00
|
|
|
padata_reorder(pd);
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(padata_do_serial);
|
|
|
|
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
static int padata_setup_cpumasks(struct padata_instance *pinst)
|
2010-01-06 08:47:10 +00:00
|
|
|
{
|
2019-09-06 01:40:28 +00:00
|
|
|
struct workqueue_attrs *attrs;
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
int err;
|
|
|
|
|
|
|
|
attrs = alloc_workqueue_attrs();
|
|
|
|
if (!attrs)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
/* Restrict parallel_wq workers to pd->cpumask.pcpu. */
|
|
|
|
cpumask_copy(attrs->cpumask, pinst->cpumask.pcpu);
|
|
|
|
err = apply_workqueue_attrs(pinst->parallel_wq, attrs);
|
|
|
|
free_workqueue_attrs(attrs);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-06-03 22:59:43 +00:00
|
|
|
static void __init padata_mt_helper(struct work_struct *w)
|
|
|
|
{
|
|
|
|
struct padata_work *pw = container_of(w, struct padata_work, pw_work);
|
|
|
|
struct padata_mt_job_state *ps = pw->pw_data;
|
|
|
|
struct padata_mt_job *job = ps->job;
|
|
|
|
bool done;
|
|
|
|
|
|
|
|
spin_lock(&ps->lock);
|
|
|
|
|
|
|
|
while (job->size > 0) {
|
|
|
|
unsigned long start, size, end;
|
|
|
|
|
|
|
|
start = job->start;
|
|
|
|
/* So end is chunk size aligned if enough work remains. */
|
|
|
|
size = roundup(start + 1, ps->chunk_size) - start;
|
|
|
|
size = min(size, job->size);
|
|
|
|
end = start + size;
|
|
|
|
|
|
|
|
job->start = end;
|
|
|
|
job->size -= size;
|
|
|
|
|
|
|
|
spin_unlock(&ps->lock);
|
|
|
|
job->thread_fn(start, end, job->fn_arg);
|
|
|
|
spin_lock(&ps->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
++ps->nworks_fini;
|
|
|
|
done = (ps->nworks_fini == ps->nworks);
|
|
|
|
spin_unlock(&ps->lock);
|
|
|
|
|
|
|
|
if (done)
|
|
|
|
complete(&ps->completion);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* padata_do_multithreaded - run a multithreaded job
|
|
|
|
* @job: Description of the job.
|
|
|
|
*
|
|
|
|
* See the definition of struct padata_mt_job for more details.
|
|
|
|
*/
|
|
|
|
void __init padata_do_multithreaded(struct padata_mt_job *job)
|
|
|
|
{
|
|
|
|
/* In case threads finish at different times. */
|
|
|
|
static const unsigned long load_balance_factor = 4;
|
|
|
|
struct padata_work my_work, *pw;
|
|
|
|
struct padata_mt_job_state ps;
|
|
|
|
LIST_HEAD(works);
|
2024-03-06 21:04:17 +00:00
|
|
|
int nworks, nid;
|
|
|
|
static atomic_t last_used_nid __initdata;
|
2020-06-03 22:59:43 +00:00
|
|
|
|
|
|
|
if (job->size == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Ensure at least one thread when size < min_chunk. */
|
2023-02-23 00:33:12 +00:00
|
|
|
nworks = max(job->size / max(job->min_chunk, job->align), 1ul);
|
2020-06-03 22:59:43 +00:00
|
|
|
nworks = min(nworks, job->max_threads);
|
|
|
|
|
|
|
|
if (nworks == 1) {
|
|
|
|
/* Single thread, no coordination needed, cut to the chase. */
|
|
|
|
job->thread_fn(job->start, job->start + job->size, job->fn_arg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock_init(&ps.lock);
|
|
|
|
init_completion(&ps.completion);
|
|
|
|
ps.job = job;
|
|
|
|
ps.nworks = padata_work_alloc_mt(nworks, &ps, &works);
|
|
|
|
ps.nworks_fini = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Chunk size is the amount of work a helper does per call to the
|
|
|
|
* thread function. Load balance large jobs between threads by
|
|
|
|
* increasing the number of chunks, guarantee at least the minimum
|
|
|
|
* chunk size from the caller, and honor the caller's alignment.
|
2024-08-21 21:02:52 +00:00
|
|
|
* Ensure chunk_size is at least 1 to prevent divide-by-0
|
|
|
|
* panic in padata_mt_helper().
|
2020-06-03 22:59:43 +00:00
|
|
|
*/
|
|
|
|
ps.chunk_size = job->size / (ps.nworks * load_balance_factor);
|
|
|
|
ps.chunk_size = max(ps.chunk_size, job->min_chunk);
|
2024-08-21 21:02:52 +00:00
|
|
|
ps.chunk_size = max(ps.chunk_size, 1ul);
|
2020-06-03 22:59:43 +00:00
|
|
|
ps.chunk_size = roundup(ps.chunk_size, job->align);
|
|
|
|
|
|
|
|
list_for_each_entry(pw, &works, pw_list)
|
2024-03-06 21:04:17 +00:00
|
|
|
if (job->numa_aware) {
|
|
|
|
int old_node = atomic_read(&last_used_nid);
|
|
|
|
|
|
|
|
do {
|
|
|
|
nid = next_node_in(old_node, node_states[N_CPU]);
|
|
|
|
} while (!atomic_try_cmpxchg(&last_used_nid, &old_node, nid));
|
|
|
|
queue_work_node(nid, system_unbound_wq, &pw->pw_work);
|
|
|
|
} else {
|
|
|
|
queue_work(system_unbound_wq, &pw->pw_work);
|
|
|
|
}
|
2020-06-03 22:59:43 +00:00
|
|
|
|
|
|
|
/* Use the current thread, which saves starting a workqueue worker. */
|
|
|
|
padata_work_init(&my_work, padata_mt_helper, &ps, PADATA_WORK_ONSTACK);
|
|
|
|
padata_mt_helper(&my_work.pw_work);
|
|
|
|
|
|
|
|
/* Wait for all the helpers to finish. */
|
|
|
|
wait_for_completion(&ps.completion);
|
|
|
|
|
|
|
|
destroy_work_on_stack(&my_work.pw_work);
|
|
|
|
padata_works_free(&works);
|
|
|
|
}
|
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
static void __padata_list_init(struct padata_list *pd_list)
|
|
|
|
{
|
|
|
|
INIT_LIST_HEAD(&pd_list->list);
|
|
|
|
spin_lock_init(&pd_list->lock);
|
|
|
|
}
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
/* Initialize all percpu queues used by serial workers */
|
|
|
|
static void padata_init_squeues(struct parallel_data *pd)
|
|
|
|
{
|
|
|
|
int cpu;
|
|
|
|
struct padata_serial_queue *squeue;
|
2010-04-29 12:41:36 +00:00
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
for_each_cpu(cpu, pd->cpumask.cbcpu) {
|
|
|
|
squeue = per_cpu_ptr(pd->squeue, cpu);
|
|
|
|
squeue->pd = pd;
|
|
|
|
__padata_list_init(&squeue->serial);
|
|
|
|
INIT_WORK(&squeue->work, padata_serial_worker);
|
|
|
|
}
|
|
|
|
}
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-07-14 20:13:56 +00:00
|
|
|
/* Initialize per-CPU reorder lists */
|
|
|
|
static void padata_init_reorder_list(struct parallel_data *pd)
|
2010-07-14 10:31:57 +00:00
|
|
|
{
|
2019-09-06 01:40:29 +00:00
|
|
|
int cpu;
|
2020-07-14 20:13:56 +00:00
|
|
|
struct padata_list *list;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2019-09-06 01:40:29 +00:00
|
|
|
for_each_cpu(cpu, pd->cpumask.pcpu) {
|
2020-07-14 20:13:56 +00:00
|
|
|
list = per_cpu_ptr(pd->reorder_list, cpu);
|
|
|
|
__padata_list_init(list);
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
2010-07-14 10:31:57 +00:00
|
|
|
}
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
/* Allocate and initialize the internal cpumask dependend resources. */
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
static struct parallel_data *padata_alloc_pd(struct padata_shell *ps)
|
2010-07-14 10:31:57 +00:00
|
|
|
{
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
struct padata_instance *pinst = ps->pinst;
|
2010-07-14 10:31:57 +00:00
|
|
|
struct parallel_data *pd;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
pd = kzalloc(sizeof(struct parallel_data), GFP_KERNEL);
|
|
|
|
if (!pd)
|
|
|
|
goto err;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-07-14 20:13:56 +00:00
|
|
|
pd->reorder_list = alloc_percpu(struct padata_list);
|
|
|
|
if (!pd->reorder_list)
|
2010-07-14 10:31:57 +00:00
|
|
|
goto err_free_pd;
|
|
|
|
|
|
|
|
pd->squeue = alloc_percpu(struct padata_serial_queue);
|
|
|
|
if (!pd->squeue)
|
2020-07-14 20:13:56 +00:00
|
|
|
goto err_free_reorder_list;
|
2019-09-06 01:40:28 +00:00
|
|
|
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
pd->ps = ps;
|
2020-07-14 20:13:53 +00:00
|
|
|
|
|
|
|
if (!alloc_cpumask_var(&pd->cpumask.pcpu, GFP_KERNEL))
|
2010-07-14 10:31:57 +00:00
|
|
|
goto err_free_squeue;
|
2020-07-14 20:13:53 +00:00
|
|
|
if (!alloc_cpumask_var(&pd->cpumask.cbcpu, GFP_KERNEL))
|
|
|
|
goto err_free_pcpu;
|
|
|
|
|
2020-07-14 20:13:54 +00:00
|
|
|
cpumask_and(pd->cpumask.pcpu, pinst->cpumask.pcpu, cpu_online_mask);
|
|
|
|
cpumask_and(pd->cpumask.cbcpu, pinst->cpumask.cbcpu, cpu_online_mask);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-07-14 20:13:56 +00:00
|
|
|
padata_init_reorder_list(pd);
|
2010-07-14 10:31:57 +00:00
|
|
|
padata_init_squeues(pd);
|
2020-06-03 22:59:39 +00:00
|
|
|
pd->seq_nr = -1;
|
2021-07-20 15:05:11 +00:00
|
|
|
refcount_set(&pd->refcnt, 1);
|
2010-01-06 08:47:10 +00:00
|
|
|
spin_lock_init(&pd->lock);
|
2019-08-08 16:05:35 +00:00
|
|
|
pd->cpu = cpumask_first(pd->cpumask.pcpu);
|
2019-07-18 15:01:46 +00:00
|
|
|
INIT_WORK(&pd->reorder_work, invoke_padata_reorder);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
|
|
|
return pd;
|
|
|
|
|
2020-07-14 20:13:53 +00:00
|
|
|
err_free_pcpu:
|
|
|
|
free_cpumask_var(pd->cpumask.pcpu);
|
2010-07-14 10:31:57 +00:00
|
|
|
err_free_squeue:
|
|
|
|
free_percpu(pd->squeue);
|
2020-07-14 20:13:56 +00:00
|
|
|
err_free_reorder_list:
|
|
|
|
free_percpu(pd->reorder_list);
|
2010-01-06 08:47:10 +00:00
|
|
|
err_free_pd:
|
|
|
|
kfree(pd);
|
|
|
|
err:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void padata_free_pd(struct parallel_data *pd)
|
|
|
|
{
|
2010-07-14 10:31:57 +00:00
|
|
|
free_cpumask_var(pd->cpumask.pcpu);
|
|
|
|
free_cpumask_var(pd->cpumask.cbcpu);
|
2020-07-14 20:13:56 +00:00
|
|
|
free_percpu(pd->reorder_list);
|
2010-07-14 10:31:57 +00:00
|
|
|
free_percpu(pd->squeue);
|
2010-01-06 08:47:10 +00:00
|
|
|
kfree(pd);
|
|
|
|
}
|
|
|
|
|
2010-07-07 13:30:10 +00:00
|
|
|
static void __padata_start(struct padata_instance *pinst)
|
|
|
|
{
|
|
|
|
pinst->flags |= PADATA_INIT;
|
|
|
|
}
|
|
|
|
|
2010-07-07 13:30:47 +00:00
|
|
|
static void __padata_stop(struct padata_instance *pinst)
|
|
|
|
{
|
|
|
|
if (!(pinst->flags & PADATA_INIT))
|
|
|
|
return;
|
|
|
|
|
|
|
|
pinst->flags &= ~PADATA_INIT;
|
|
|
|
|
|
|
|
synchronize_rcu();
|
|
|
|
}
|
|
|
|
|
2011-03-31 01:57:33 +00:00
|
|
|
/* Replace the internal control structure with a new one. */
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
static int padata_replace_one(struct padata_shell *ps)
|
2010-01-06 08:47:10 +00:00
|
|
|
{
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
struct parallel_data *pd_new;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
pd_new = padata_alloc_pd(ps);
|
|
|
|
if (!pd_new)
|
|
|
|
return -ENOMEM;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
ps->opd = rcu_dereference_protected(ps->pd, 1);
|
|
|
|
rcu_assign_pointer(ps->pd, pd_new);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-12-03 19:31:10 +00:00
|
|
|
static int padata_replace(struct padata_instance *pinst)
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
{
|
|
|
|
struct padata_shell *ps;
|
2020-02-10 18:11:00 +00:00
|
|
|
int err = 0;
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
|
|
|
|
pinst->flags |= PADATA_RESET;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
list_for_each_entry(ps, &pinst->pslist, list) {
|
|
|
|
err = padata_replace_one(ps);
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
synchronize_rcu();
|
|
|
|
|
|
|
|
list_for_each_entry_continue_reverse(ps, &pinst->pslist, list)
|
2021-07-20 15:05:11 +00:00
|
|
|
if (refcount_dec_and_test(&ps->opd->refcnt))
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
padata_free_pd(ps->opd);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
|
|
|
pinst->flags &= ~PADATA_RESET;
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
|
|
|
|
return err;
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
|
2010-07-07 13:31:26 +00:00
|
|
|
/* If cpumask contains no active cpu, we mark the instance as invalid. */
|
|
|
|
static bool padata_validate_cpumask(struct padata_instance *pinst,
|
|
|
|
const struct cpumask *cpumask)
|
|
|
|
{
|
2012-03-28 06:43:21 +00:00
|
|
|
if (!cpumask_intersects(cpumask, cpu_online_mask)) {
|
2010-07-07 13:31:26 +00:00
|
|
|
pinst->flags |= PADATA_INVALID;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
pinst->flags &= ~PADATA_INVALID;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-07-27 05:15:06 +00:00
|
|
|
static int __padata_set_cpumasks(struct padata_instance *pinst,
|
|
|
|
cpumask_var_t pcpumask,
|
|
|
|
cpumask_var_t cbcpumask)
|
|
|
|
{
|
|
|
|
int valid;
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
int err;
|
2010-07-27 05:15:06 +00:00
|
|
|
|
|
|
|
valid = padata_validate_cpumask(pinst, pcpumask);
|
|
|
|
if (!valid) {
|
|
|
|
__padata_stop(pinst);
|
|
|
|
goto out_replace;
|
|
|
|
}
|
|
|
|
|
|
|
|
valid = padata_validate_cpumask(pinst, cbcpumask);
|
|
|
|
if (!valid)
|
|
|
|
__padata_stop(pinst);
|
|
|
|
|
|
|
|
out_replace:
|
|
|
|
cpumask_copy(pinst->cpumask.pcpu, pcpumask);
|
|
|
|
cpumask_copy(pinst->cpumask.cbcpu, cbcpumask);
|
|
|
|
|
2019-12-03 19:31:10 +00:00
|
|
|
err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst);
|
2010-07-27 05:15:06 +00:00
|
|
|
|
|
|
|
if (valid)
|
|
|
|
__padata_start(pinst);
|
|
|
|
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
return err;
|
2010-07-27 05:15:06 +00:00
|
|
|
}
|
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
/**
|
2019-12-03 19:31:14 +00:00
|
|
|
* padata_set_cpumask - Sets specified by @cpumask_type cpumask to the value
|
|
|
|
* equivalent to @cpumask.
|
2010-01-06 08:47:10 +00:00
|
|
|
* @pinst: padata instance
|
2010-07-14 10:31:57 +00:00
|
|
|
* @cpumask_type: PADATA_CPU_SERIAL or PADATA_CPU_PARALLEL corresponding
|
|
|
|
* to parallel and serial cpumasks respectively.
|
2010-01-06 08:47:10 +00:00
|
|
|
* @cpumask: the cpumask to use
|
2019-12-03 19:31:14 +00:00
|
|
|
*
|
|
|
|
* Return: 0 on success or negative error code
|
2010-01-06 08:47:10 +00:00
|
|
|
*/
|
2010-07-14 10:31:57 +00:00
|
|
|
int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type,
|
|
|
|
cpumask_var_t cpumask)
|
|
|
|
{
|
|
|
|
struct cpumask *serial_mask, *parallel_mask;
|
2010-07-27 05:15:06 +00:00
|
|
|
int err = -EINVAL;
|
|
|
|
|
2021-08-03 14:16:10 +00:00
|
|
|
cpus_read_lock();
|
2019-12-03 19:31:11 +00:00
|
|
|
mutex_lock(&pinst->lock);
|
2010-04-29 12:42:30 +00:00
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
switch (cpumask_type) {
|
|
|
|
case PADATA_CPU_PARALLEL:
|
|
|
|
serial_mask = pinst->cpumask.cbcpu;
|
|
|
|
parallel_mask = cpumask;
|
|
|
|
break;
|
|
|
|
case PADATA_CPU_SERIAL:
|
|
|
|
parallel_mask = pinst->cpumask.pcpu;
|
|
|
|
serial_mask = cpumask;
|
|
|
|
break;
|
|
|
|
default:
|
2010-07-27 05:15:06 +00:00
|
|
|
goto out;
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
|
2010-07-27 05:15:06 +00:00
|
|
|
err = __padata_set_cpumasks(pinst, parallel_mask, serial_mask);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
mutex_unlock(&pinst->lock);
|
2021-08-03 14:16:10 +00:00
|
|
|
cpus_read_unlock();
|
2010-01-06 08:47:10 +00:00
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(padata_set_cpumask);
|
|
|
|
|
2016-05-20 00:09:59 +00:00
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
|
|
|
2010-01-06 08:47:10 +00:00
|
|
|
static int __padata_add_cpu(struct padata_instance *pinst, int cpu)
|
|
|
|
{
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
int err = 0;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2012-03-28 06:43:21 +00:00
|
|
|
if (cpumask_test_cpu(cpu, cpu_online_mask)) {
|
2019-12-03 19:31:10 +00:00
|
|
|
err = padata_replace(pinst);
|
2010-07-07 13:31:26 +00:00
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) &&
|
|
|
|
padata_validate_cpumask(pinst, pinst->cpumask.cbcpu))
|
2010-07-07 13:31:26 +00:00
|
|
|
__padata_start(pinst);
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
return err;
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int __padata_remove_cpu(struct padata_instance *pinst, int cpu)
|
|
|
|
{
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
int err = 0;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2019-12-03 19:31:10 +00:00
|
|
|
if (!cpumask_test_cpu(cpu, cpu_online_mask)) {
|
2010-07-14 10:31:57 +00:00
|
|
|
if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) ||
|
2010-07-20 06:49:20 +00:00
|
|
|
!padata_validate_cpumask(pinst, pinst->cpumask.cbcpu))
|
2010-07-07 13:31:26 +00:00
|
|
|
__padata_stop(pinst);
|
|
|
|
|
2019-12-03 19:31:10 +00:00
|
|
|
err = padata_replace(pinst);
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
return err;
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu)
|
|
|
|
{
|
|
|
|
return cpumask_test_cpu(cpu, pinst->cpumask.pcpu) ||
|
|
|
|
cpumask_test_cpu(cpu, pinst->cpumask.cbcpu);
|
|
|
|
}
|
|
|
|
|
2016-09-06 17:04:49 +00:00
|
|
|
static int padata_cpu_online(unsigned int cpu, struct hlist_node *node)
|
2010-01-06 08:47:10 +00:00
|
|
|
{
|
|
|
|
struct padata_instance *pinst;
|
2016-09-06 17:04:49 +00:00
|
|
|
int ret;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-04-21 16:34:55 +00:00
|
|
|
pinst = hlist_entry_safe(node, struct padata_instance, cpu_online_node);
|
2016-09-06 17:04:49 +00:00
|
|
|
if (!pinst_has_cpu(pinst, cpu))
|
|
|
|
return 0;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2016-09-06 17:04:49 +00:00
|
|
|
mutex_lock(&pinst->lock);
|
|
|
|
ret = __padata_add_cpu(pinst, cpu);
|
|
|
|
mutex_unlock(&pinst->lock);
|
|
|
|
return ret;
|
|
|
|
}
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2019-12-03 19:31:10 +00:00
|
|
|
static int padata_cpu_dead(unsigned int cpu, struct hlist_node *node)
|
2016-09-06 17:04:49 +00:00
|
|
|
{
|
|
|
|
struct padata_instance *pinst;
|
|
|
|
int ret;
|
|
|
|
|
2020-04-21 16:34:55 +00:00
|
|
|
pinst = hlist_entry_safe(node, struct padata_instance, cpu_dead_node);
|
2016-09-06 17:04:49 +00:00
|
|
|
if (!pinst_has_cpu(pinst, cpu))
|
|
|
|
return 0;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2016-09-06 17:04:49 +00:00
|
|
|
mutex_lock(&pinst->lock);
|
|
|
|
ret = __padata_remove_cpu(pinst, cpu);
|
|
|
|
mutex_unlock(&pinst->lock);
|
|
|
|
return ret;
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
2016-09-06 17:04:49 +00:00
|
|
|
|
|
|
|
static enum cpuhp_state hp_online;
|
2010-04-29 12:40:10 +00:00
|
|
|
#endif
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2010-07-14 10:33:08 +00:00
|
|
|
static void __padata_free(struct padata_instance *pinst)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
2020-04-21 16:34:55 +00:00
|
|
|
cpuhp_state_remove_instance_nocalls(CPUHP_PADATA_DEAD,
|
|
|
|
&pinst->cpu_dead_node);
|
|
|
|
cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpu_online_node);
|
2010-07-14 10:33:08 +00:00
|
|
|
#endif
|
|
|
|
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
WARN_ON(!list_empty(&pinst->pslist));
|
|
|
|
|
2010-07-14 10:33:08 +00:00
|
|
|
free_cpumask_var(pinst->cpumask.pcpu);
|
|
|
|
free_cpumask_var(pinst->cpumask.cbcpu);
|
2019-09-06 01:40:27 +00:00
|
|
|
destroy_workqueue(pinst->serial_wq);
|
|
|
|
destroy_workqueue(pinst->parallel_wq);
|
2010-07-14 10:33:08 +00:00
|
|
|
kfree(pinst);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define kobj2pinst(_kobj) \
|
|
|
|
container_of(_kobj, struct padata_instance, kobj)
|
|
|
|
#define attr2pentry(_attr) \
|
|
|
|
container_of(_attr, struct padata_sysfs_entry, attr)
|
|
|
|
|
|
|
|
static void padata_sysfs_release(struct kobject *kobj)
|
|
|
|
{
|
|
|
|
struct padata_instance *pinst = kobj2pinst(kobj);
|
|
|
|
__padata_free(pinst);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct padata_sysfs_entry {
|
|
|
|
struct attribute attr;
|
|
|
|
ssize_t (*show)(struct padata_instance *, struct attribute *, char *);
|
|
|
|
ssize_t (*store)(struct padata_instance *, struct attribute *,
|
|
|
|
const char *, size_t);
|
|
|
|
};
|
|
|
|
|
|
|
|
static ssize_t show_cpumask(struct padata_instance *pinst,
|
|
|
|
struct attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct cpumask *cpumask;
|
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
mutex_lock(&pinst->lock);
|
|
|
|
if (!strcmp(attr->name, "serial_cpumask"))
|
|
|
|
cpumask = pinst->cpumask.cbcpu;
|
|
|
|
else
|
|
|
|
cpumask = pinst->cpumask.pcpu;
|
|
|
|
|
2015-02-13 22:38:05 +00:00
|
|
|
len = snprintf(buf, PAGE_SIZE, "%*pb\n",
|
|
|
|
nr_cpu_ids, cpumask_bits(cpumask));
|
2010-07-14 10:33:08 +00:00
|
|
|
mutex_unlock(&pinst->lock);
|
2015-02-13 22:38:05 +00:00
|
|
|
return len < PAGE_SIZE ? len : -EINVAL;
|
2010-07-14 10:33:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t store_cpumask(struct padata_instance *pinst,
|
|
|
|
struct attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
|
|
cpumask_var_t new_cpumask;
|
|
|
|
ssize_t ret;
|
|
|
|
int mask_type;
|
|
|
|
|
|
|
|
if (!alloc_cpumask_var(&new_cpumask, GFP_KERNEL))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
ret = bitmap_parse(buf, count, cpumask_bits(new_cpumask),
|
|
|
|
nr_cpumask_bits);
|
|
|
|
if (ret < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
mask_type = !strcmp(attr->name, "serial_cpumask") ?
|
|
|
|
PADATA_CPU_SERIAL : PADATA_CPU_PARALLEL;
|
|
|
|
ret = padata_set_cpumask(pinst, mask_type, new_cpumask);
|
|
|
|
if (!ret)
|
|
|
|
ret = count;
|
|
|
|
|
|
|
|
out:
|
|
|
|
free_cpumask_var(new_cpumask);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define PADATA_ATTR_RW(_name, _show_name, _store_name) \
|
|
|
|
static struct padata_sysfs_entry _name##_attr = \
|
|
|
|
__ATTR(_name, 0644, _show_name, _store_name)
|
|
|
|
#define PADATA_ATTR_RO(_name, _show_name) \
|
|
|
|
static struct padata_sysfs_entry _name##_attr = \
|
|
|
|
__ATTR(_name, 0400, _show_name, NULL)
|
|
|
|
|
|
|
|
PADATA_ATTR_RW(serial_cpumask, show_cpumask, store_cpumask);
|
|
|
|
PADATA_ATTR_RW(parallel_cpumask, show_cpumask, store_cpumask);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Padata sysfs provides the following objects:
|
|
|
|
* serial_cpumask [RW] - cpumask for serial workers
|
|
|
|
* parallel_cpumask [RW] - cpumask for parallel workers
|
|
|
|
*/
|
|
|
|
static struct attribute *padata_default_attrs[] = {
|
|
|
|
&serial_cpumask_attr.attr,
|
|
|
|
¶llel_cpumask_attr.attr,
|
|
|
|
NULL,
|
|
|
|
};
|
2019-04-02 02:51:47 +00:00
|
|
|
ATTRIBUTE_GROUPS(padata_default);
|
2010-07-14 10:33:08 +00:00
|
|
|
|
|
|
|
static ssize_t padata_sysfs_show(struct kobject *kobj,
|
|
|
|
struct attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct padata_instance *pinst;
|
|
|
|
struct padata_sysfs_entry *pentry;
|
|
|
|
ssize_t ret = -EIO;
|
|
|
|
|
|
|
|
pinst = kobj2pinst(kobj);
|
|
|
|
pentry = attr2pentry(attr);
|
|
|
|
if (pentry->show)
|
|
|
|
ret = pentry->show(pinst, attr, buf);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t padata_sysfs_store(struct kobject *kobj, struct attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
|
|
struct padata_instance *pinst;
|
|
|
|
struct padata_sysfs_entry *pentry;
|
|
|
|
ssize_t ret = -EIO;
|
|
|
|
|
|
|
|
pinst = kobj2pinst(kobj);
|
|
|
|
pentry = attr2pentry(attr);
|
|
|
|
if (pentry->show)
|
|
|
|
ret = pentry->store(pinst, attr, buf, count);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct sysfs_ops padata_sysfs_ops = {
|
|
|
|
.show = padata_sysfs_show,
|
|
|
|
.store = padata_sysfs_store,
|
|
|
|
};
|
|
|
|
|
2023-02-17 03:17:49 +00:00
|
|
|
static const struct kobj_type padata_attr_type = {
|
2010-07-14 10:33:08 +00:00
|
|
|
.sysfs_ops = &padata_sysfs_ops,
|
2019-04-02 02:51:47 +00:00
|
|
|
.default_groups = padata_default_groups,
|
2010-07-14 10:33:08 +00:00
|
|
|
.release = padata_sysfs_release,
|
|
|
|
};
|
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
/**
|
2020-07-14 20:13:55 +00:00
|
|
|
* padata_alloc - allocate and initialize a padata instance
|
2019-09-06 01:40:21 +00:00
|
|
|
* @name: used to identify the instance
|
2019-12-03 19:31:14 +00:00
|
|
|
*
|
|
|
|
* Return: new instance on success, NULL on error
|
2010-01-06 08:47:10 +00:00
|
|
|
*/
|
2020-07-14 20:13:55 +00:00
|
|
|
struct padata_instance *padata_alloc(const char *name)
|
2010-01-06 08:47:10 +00:00
|
|
|
{
|
|
|
|
struct padata_instance *pinst;
|
|
|
|
|
|
|
|
pinst = kzalloc(sizeof(struct padata_instance), GFP_KERNEL);
|
|
|
|
if (!pinst)
|
|
|
|
goto err;
|
|
|
|
|
2019-09-06 01:40:28 +00:00
|
|
|
pinst->parallel_wq = alloc_workqueue("%s_parallel", WQ_UNBOUND, 0,
|
|
|
|
name);
|
2019-09-06 01:40:27 +00:00
|
|
|
if (!pinst->parallel_wq)
|
2010-01-06 08:47:10 +00:00
|
|
|
goto err_free_inst;
|
2019-09-06 01:40:21 +00:00
|
|
|
|
2021-08-03 14:16:10 +00:00
|
|
|
cpus_read_lock();
|
2019-09-06 01:40:26 +00:00
|
|
|
|
2019-09-06 01:40:27 +00:00
|
|
|
pinst->serial_wq = alloc_workqueue("%s_serial", WQ_MEM_RECLAIM |
|
|
|
|
WQ_CPU_INTENSIVE, 1, name);
|
|
|
|
if (!pinst->serial_wq)
|
2019-09-06 01:40:26 +00:00
|
|
|
goto err_put_cpus;
|
2019-09-06 01:40:27 +00:00
|
|
|
|
|
|
|
if (!alloc_cpumask_var(&pinst->cpumask.pcpu, GFP_KERNEL))
|
|
|
|
goto err_free_serial_wq;
|
2010-07-14 10:31:57 +00:00
|
|
|
if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) {
|
|
|
|
free_cpumask_var(pinst->cpumask.pcpu);
|
2019-09-06 01:40:27 +00:00
|
|
|
goto err_free_serial_wq;
|
2010-07-07 13:31:26 +00:00
|
|
|
}
|
2010-01-06 08:47:10 +00:00
|
|
|
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
INIT_LIST_HEAD(&pinst->pslist);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-07-14 20:13:55 +00:00
|
|
|
cpumask_copy(pinst->cpumask.pcpu, cpu_possible_mask);
|
|
|
|
cpumask_copy(pinst->cpumask.cbcpu, cpu_possible_mask);
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
|
|
|
|
if (padata_setup_cpumasks(pinst))
|
2020-07-14 20:13:54 +00:00
|
|
|
goto err_free_masks;
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2020-07-14 20:13:51 +00:00
|
|
|
__padata_start(pinst);
|
2010-01-06 08:47:10 +00:00
|
|
|
|
2010-07-14 10:33:08 +00:00
|
|
|
kobject_init(&pinst->kobj, &padata_attr_type);
|
2010-01-06 08:47:10 +00:00
|
|
|
mutex_init(&pinst->lock);
|
|
|
|
|
2013-08-23 11:12:33 +00:00
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
2020-04-21 16:34:55 +00:00
|
|
|
cpuhp_state_add_instance_nocalls_cpuslocked(hp_online,
|
|
|
|
&pinst->cpu_online_node);
|
2019-12-03 19:31:10 +00:00
|
|
|
cpuhp_state_add_instance_nocalls_cpuslocked(CPUHP_PADATA_DEAD,
|
2020-04-21 16:34:55 +00:00
|
|
|
&pinst->cpu_dead_node);
|
2013-08-23 11:12:33 +00:00
|
|
|
#endif
|
2019-09-06 01:40:26 +00:00
|
|
|
|
2021-08-03 14:16:10 +00:00
|
|
|
cpus_read_unlock();
|
2019-09-06 01:40:26 +00:00
|
|
|
|
2010-01-06 08:47:10 +00:00
|
|
|
return pinst;
|
|
|
|
|
2010-07-14 10:31:57 +00:00
|
|
|
err_free_masks:
|
|
|
|
free_cpumask_var(pinst->cpumask.pcpu);
|
|
|
|
free_cpumask_var(pinst->cpumask.cbcpu);
|
2019-09-06 01:40:27 +00:00
|
|
|
err_free_serial_wq:
|
|
|
|
destroy_workqueue(pinst->serial_wq);
|
2019-09-06 01:40:26 +00:00
|
|
|
err_put_cpus:
|
2021-08-03 14:16:10 +00:00
|
|
|
cpus_read_unlock();
|
2019-09-06 01:40:27 +00:00
|
|
|
destroy_workqueue(pinst->parallel_wq);
|
2010-01-06 08:47:10 +00:00
|
|
|
err_free_inst:
|
|
|
|
kfree(pinst);
|
|
|
|
err:
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-07-14 20:13:55 +00:00
|
|
|
EXPORT_SYMBOL(padata_alloc);
|
2017-05-24 08:15:17 +00:00
|
|
|
|
2010-05-19 03:44:27 +00:00
|
|
|
/**
|
2010-01-06 08:47:10 +00:00
|
|
|
* padata_free - free a padata instance
|
|
|
|
*
|
2019-12-03 19:31:14 +00:00
|
|
|
* @pinst: padata instance to free
|
2010-01-06 08:47:10 +00:00
|
|
|
*/
|
|
|
|
void padata_free(struct padata_instance *pinst)
|
|
|
|
{
|
2010-07-14 10:33:08 +00:00
|
|
|
kobject_put(&pinst->kobj);
|
2010-01-06 08:47:10 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(padata_free);
|
2016-09-06 17:04:49 +00:00
|
|
|
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
/**
|
|
|
|
* padata_alloc_shell - Allocate and initialize padata shell.
|
|
|
|
*
|
|
|
|
* @pinst: Parent padata_instance object.
|
2019-12-03 19:31:14 +00:00
|
|
|
*
|
|
|
|
* Return: new shell on success, NULL on error
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
*/
|
|
|
|
struct padata_shell *padata_alloc_shell(struct padata_instance *pinst)
|
|
|
|
{
|
|
|
|
struct parallel_data *pd;
|
|
|
|
struct padata_shell *ps;
|
|
|
|
|
|
|
|
ps = kzalloc(sizeof(*ps), GFP_KERNEL);
|
|
|
|
if (!ps)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
ps->pinst = pinst;
|
|
|
|
|
2021-08-03 14:16:10 +00:00
|
|
|
cpus_read_lock();
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
pd = padata_alloc_pd(ps);
|
2021-08-03 14:16:10 +00:00
|
|
|
cpus_read_unlock();
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
|
|
|
|
if (!pd)
|
|
|
|
goto out_free_ps;
|
|
|
|
|
|
|
|
mutex_lock(&pinst->lock);
|
|
|
|
RCU_INIT_POINTER(ps->pd, pd);
|
|
|
|
list_add(&ps->list, &pinst->pslist);
|
|
|
|
mutex_unlock(&pinst->lock);
|
|
|
|
|
|
|
|
return ps;
|
|
|
|
|
|
|
|
out_free_ps:
|
|
|
|
kfree(ps);
|
|
|
|
out:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(padata_alloc_shell);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* padata_free_shell - free a padata shell
|
|
|
|
*
|
|
|
|
* @ps: padata shell to free
|
|
|
|
*/
|
|
|
|
void padata_free_shell(struct padata_shell *ps)
|
|
|
|
{
|
padata: Fix refcnt handling in padata_free_shell()
In a high-load arm64 environment, the pcrypt_aead01 test in LTP can lead
to system UAF (Use-After-Free) issues. Due to the lengthy analysis of
the pcrypt_aead01 function call, I'll describe the problem scenario
using a simplified model:
Suppose there's a user of padata named `user_function` that adheres to
the padata requirement of calling `padata_free_shell` after `serial()`
has been invoked, as demonstrated in the following code:
```c
struct request {
struct padata_priv padata;
struct completion *done;
};
void parallel(struct padata_priv *padata) {
do_something();
}
void serial(struct padata_priv *padata) {
struct request *request = container_of(padata,
struct request,
padata);
complete(request->done);
}
void user_function() {
DECLARE_COMPLETION(done)
padata->parallel = parallel;
padata->serial = serial;
padata_do_parallel();
wait_for_completion(&done);
padata_free_shell();
}
```
In the corresponding padata.c file, there's the following code:
```c
static void padata_serial_worker(struct work_struct *serial_work) {
...
cnt = 0;
while (!list_empty(&local_list)) {
...
padata->serial(padata);
cnt++;
}
local_bh_enable();
if (refcount_sub_and_test(cnt, &pd->refcnt))
padata_free_pd(pd);
}
```
Because of the high system load and the accumulation of unexecuted
softirq at this moment, `local_bh_enable()` in padata takes longer
to execute than usual. Subsequently, when accessing `pd->refcnt`,
`pd` has already been released by `padata_free_shell()`, resulting
in a UAF issue with `pd->refcnt`.
The fix is straightforward: add `refcount_dec_and_test` before calling
`padata_free_pd` in `padata_free_shell`.
Fixes: 07928d9bfc81 ("padata: Remove broken queue flushing")
Signed-off-by: WangJinchao <wangjinchao@xfusion.com>
Acked-by: Daniel Jordan <daniel.m.jordan@oracle.com>
Acked-by: Daniel Jordan <daniel.m.jordan@oracle.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2023-10-16 01:15:21 +00:00
|
|
|
struct parallel_data *pd;
|
|
|
|
|
2020-02-26 04:59:22 +00:00
|
|
|
if (!ps)
|
|
|
|
return;
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
|
2020-02-26 04:59:22 +00:00
|
|
|
mutex_lock(&ps->pinst->lock);
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
list_del(&ps->list);
|
padata: Fix refcnt handling in padata_free_shell()
In a high-load arm64 environment, the pcrypt_aead01 test in LTP can lead
to system UAF (Use-After-Free) issues. Due to the lengthy analysis of
the pcrypt_aead01 function call, I'll describe the problem scenario
using a simplified model:
Suppose there's a user of padata named `user_function` that adheres to
the padata requirement of calling `padata_free_shell` after `serial()`
has been invoked, as demonstrated in the following code:
```c
struct request {
struct padata_priv padata;
struct completion *done;
};
void parallel(struct padata_priv *padata) {
do_something();
}
void serial(struct padata_priv *padata) {
struct request *request = container_of(padata,
struct request,
padata);
complete(request->done);
}
void user_function() {
DECLARE_COMPLETION(done)
padata->parallel = parallel;
padata->serial = serial;
padata_do_parallel();
wait_for_completion(&done);
padata_free_shell();
}
```
In the corresponding padata.c file, there's the following code:
```c
static void padata_serial_worker(struct work_struct *serial_work) {
...
cnt = 0;
while (!list_empty(&local_list)) {
...
padata->serial(padata);
cnt++;
}
local_bh_enable();
if (refcount_sub_and_test(cnt, &pd->refcnt))
padata_free_pd(pd);
}
```
Because of the high system load and the accumulation of unexecuted
softirq at this moment, `local_bh_enable()` in padata takes longer
to execute than usual. Subsequently, when accessing `pd->refcnt`,
`pd` has already been released by `padata_free_shell()`, resulting
in a UAF issue with `pd->refcnt`.
The fix is straightforward: add `refcount_dec_and_test` before calling
`padata_free_pd` in `padata_free_shell`.
Fixes: 07928d9bfc81 ("padata: Remove broken queue flushing")
Signed-off-by: WangJinchao <wangjinchao@xfusion.com>
Acked-by: Daniel Jordan <daniel.m.jordan@oracle.com>
Acked-by: Daniel Jordan <daniel.m.jordan@oracle.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2023-10-16 01:15:21 +00:00
|
|
|
pd = rcu_dereference_protected(ps->pd, 1);
|
|
|
|
if (refcount_dec_and_test(&pd->refcnt))
|
|
|
|
padata_free_pd(pd);
|
2020-02-26 04:59:22 +00:00
|
|
|
mutex_unlock(&ps->pinst->lock);
|
crypto: pcrypt - Avoid deadlock by using per-instance padata queues
If the pcrypt template is used multiple times in an algorithm, then a
deadlock occurs because all pcrypt instances share the same
padata_instance, which completes requests in the order submitted. That
is, the inner pcrypt request waits for the outer pcrypt request while
the outer request is already waiting for the inner.
This patch fixes this by allocating a set of queues for each pcrypt
instance instead of using two global queues. In order to maintain
the existing user-space interface, the pinst structure remains global
so any sysfs modifications will apply to every pcrypt instance.
Note that when an update occurs we have to allocate memory for
every pcrypt instance. Should one of the allocations fail we
will abort the update without rolling back changes already made.
The new per-instance data structure is called padata_shell and is
essentially a wrapper around parallel_data.
Reproducer:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "aead",
.salg_name = "pcrypt(pcrypt(rfc4106-gcm-aesni))"
};
int algfd, reqfd;
char buf[32] = { 0 };
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(algfd, (void *)&addr, sizeof(addr));
setsockopt(algfd, SOL_ALG, ALG_SET_KEY, buf, 20);
reqfd = accept(algfd, 0, 0);
write(reqfd, buf, 32);
read(reqfd, buf, 16);
}
Reported-by: syzbot+56c7151cad94eec37c521f0e47d2eee53f9361c4@syzkaller.appspotmail.com
Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto parallelization wrapper")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2019-11-26 07:58:45 +00:00
|
|
|
|
|
|
|
kfree(ps);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(padata_free_shell);
|
|
|
|
|
2020-06-03 22:59:35 +00:00
|
|
|
void __init padata_init(void)
|
2016-09-06 17:04:49 +00:00
|
|
|
{
|
2020-06-03 22:59:39 +00:00
|
|
|
unsigned int i, possible_cpus;
|
2020-06-03 22:59:35 +00:00
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
2016-09-06 17:04:49 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "padata:online",
|
2019-12-03 19:31:10 +00:00
|
|
|
padata_cpu_online, NULL);
|
2016-09-06 17:04:49 +00:00
|
|
|
if (ret < 0)
|
2020-06-03 22:59:35 +00:00
|
|
|
goto err;
|
2016-09-06 17:04:49 +00:00
|
|
|
hp_online = ret;
|
2019-12-03 19:31:10 +00:00
|
|
|
|
|
|
|
ret = cpuhp_setup_state_multi(CPUHP_PADATA_DEAD, "padata:dead",
|
|
|
|
NULL, padata_cpu_dead);
|
2020-06-03 22:59:39 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto remove_online_state;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
possible_cpus = num_possible_cpus();
|
|
|
|
padata_works = kmalloc_array(possible_cpus, sizeof(struct padata_work),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!padata_works)
|
|
|
|
goto remove_dead_state;
|
|
|
|
|
|
|
|
for (i = 0; i < possible_cpus; ++i)
|
|
|
|
list_add(&padata_works[i].pw_list, &padata_free_works);
|
2016-09-06 17:04:49 +00:00
|
|
|
|
2020-06-03 22:59:35 +00:00
|
|
|
return;
|
2020-06-03 22:59:39 +00:00
|
|
|
|
|
|
|
remove_dead_state:
|
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
|
|
cpuhp_remove_multi_state(CPUHP_PADATA_DEAD);
|
|
|
|
remove_online_state:
|
|
|
|
cpuhp_remove_multi_state(hp_online);
|
2020-06-03 22:59:35 +00:00
|
|
|
err:
|
2016-09-06 17:04:49 +00:00
|
|
|
#endif
|
2020-06-03 22:59:39 +00:00
|
|
|
pr_warn("padata: initialization failed\n");
|
2020-06-03 22:59:35 +00:00
|
|
|
}
|