![Herbert Xu](/assets/img/avatar_default.png)
commitbbefa1dd6a
upstream. 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:5068c7a883
("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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
195 lines
6.2 KiB
C
195 lines
6.2 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* padata.h - header for the padata parallelization interface
|
|
*
|
|
* Copyright (C) 2008, 2009 secunet Security Networks AG
|
|
* Copyright (C) 2008, 2009 Steffen Klassert <steffen.klassert@secunet.com>
|
|
*/
|
|
|
|
#ifndef PADATA_H
|
|
#define PADATA_H
|
|
|
|
#include <linux/compiler_types.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/list.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/kobject.h>
|
|
|
|
#define PADATA_CPU_SERIAL 0x01
|
|
#define PADATA_CPU_PARALLEL 0x02
|
|
|
|
/**
|
|
* struct padata_priv - Embedded to the users data structure.
|
|
*
|
|
* @list: List entry, to attach to the padata lists.
|
|
* @pd: Pointer to the internal control structure.
|
|
* @cb_cpu: Callback cpu for serializatioon.
|
|
* @cpu: Cpu for parallelization.
|
|
* @seq_nr: Sequence number of the parallelized data object.
|
|
* @info: Used to pass information from the parallel to the serial function.
|
|
* @parallel: Parallel execution function.
|
|
* @serial: Serial complete function.
|
|
*/
|
|
struct padata_priv {
|
|
struct list_head list;
|
|
struct parallel_data *pd;
|
|
int cb_cpu;
|
|
int cpu;
|
|
unsigned int seq_nr;
|
|
int info;
|
|
void (*parallel)(struct padata_priv *padata);
|
|
void (*serial)(struct padata_priv *padata);
|
|
};
|
|
|
|
/**
|
|
* struct padata_list
|
|
*
|
|
* @list: List head.
|
|
* @lock: List lock.
|
|
*/
|
|
struct padata_list {
|
|
struct list_head list;
|
|
spinlock_t lock;
|
|
};
|
|
|
|
/**
|
|
* struct padata_serial_queue - The percpu padata serial queue
|
|
*
|
|
* @serial: List to wait for serialization after reordering.
|
|
* @work: work struct for serialization.
|
|
* @pd: Backpointer to the internal control structure.
|
|
*/
|
|
struct padata_serial_queue {
|
|
struct padata_list serial;
|
|
struct work_struct work;
|
|
struct parallel_data *pd;
|
|
};
|
|
|
|
/**
|
|
* struct padata_parallel_queue - The percpu padata parallel queue
|
|
*
|
|
* @parallel: List to wait for parallelization.
|
|
* @reorder: List to wait for reordering after parallel processing.
|
|
* @serial: List to wait for serialization after reordering.
|
|
* @pwork: work struct for parallelization.
|
|
* @swork: work struct for serialization.
|
|
* @work: work struct for parallelization.
|
|
* @num_obj: Number of objects that are processed by this cpu.
|
|
*/
|
|
struct padata_parallel_queue {
|
|
struct padata_list parallel;
|
|
struct padata_list reorder;
|
|
struct work_struct work;
|
|
atomic_t num_obj;
|
|
};
|
|
|
|
/**
|
|
* struct padata_cpumask - The cpumasks for the parallel/serial workers
|
|
*
|
|
* @pcpu: cpumask for the parallel workers.
|
|
* @cbcpu: cpumask for the serial (callback) workers.
|
|
*/
|
|
struct padata_cpumask {
|
|
cpumask_var_t pcpu;
|
|
cpumask_var_t cbcpu;
|
|
};
|
|
|
|
/**
|
|
* struct parallel_data - Internal control structure, covers everything
|
|
* that depends on the cpumask in use.
|
|
*
|
|
* @sh: padata_shell object.
|
|
* @pqueue: percpu padata queues used for parallelization.
|
|
* @squeue: percpu padata queues used for serialuzation.
|
|
* @reorder_objects: Number of objects waiting in the reorder queues.
|
|
* @refcnt: Number of objects holding a reference on this parallel_data.
|
|
* @max_seq_nr: Maximal used sequence number.
|
|
* @processed: Number of already processed objects.
|
|
* @cpu: Next CPU to be processed.
|
|
* @cpumask: The cpumasks in use for parallel and serial workers.
|
|
* @reorder_work: work struct for reordering.
|
|
* @lock: Reorder lock.
|
|
*/
|
|
struct parallel_data {
|
|
struct padata_shell *ps;
|
|
struct padata_parallel_queue __percpu *pqueue;
|
|
struct padata_serial_queue __percpu *squeue;
|
|
atomic_t reorder_objects;
|
|
atomic_t refcnt;
|
|
atomic_t seq_nr;
|
|
unsigned int processed;
|
|
int cpu;
|
|
struct padata_cpumask cpumask;
|
|
struct work_struct reorder_work;
|
|
spinlock_t lock ____cacheline_aligned;
|
|
};
|
|
|
|
/**
|
|
* struct padata_shell - Wrapper around struct parallel_data, its
|
|
* purpose is to allow the underlying control structure to be replaced
|
|
* on the fly using RCU.
|
|
*
|
|
* @pinst: padat instance.
|
|
* @pd: Actual parallel_data structure which may be substituted on the fly.
|
|
* @opd: Pointer to old pd to be freed by padata_replace.
|
|
* @list: List entry in padata_instance list.
|
|
*/
|
|
struct padata_shell {
|
|
struct padata_instance *pinst;
|
|
struct parallel_data __rcu *pd;
|
|
struct parallel_data *opd;
|
|
struct list_head list;
|
|
};
|
|
|
|
/**
|
|
* struct padata_instance - The overall control structure.
|
|
*
|
|
* @cpu_notifier: cpu hotplug notifier.
|
|
* @parallel_wq: The workqueue used for parallel work.
|
|
* @serial_wq: The workqueue used for serial work.
|
|
* @pslist: List of padata_shell objects attached to this instance.
|
|
* @cpumask: User supplied cpumasks for parallel and serial works.
|
|
* @rcpumask: Actual cpumasks based on user cpumask and cpu_online_mask.
|
|
* @omask: Temporary storage used to compute the notification mask.
|
|
* @cpumask_change_notifier: Notifiers chain for user-defined notify
|
|
* callbacks that will be called when either @pcpu or @cbcpu
|
|
* or both cpumasks change.
|
|
* @kobj: padata instance kernel object.
|
|
* @lock: padata instance lock.
|
|
* @flags: padata flags.
|
|
*/
|
|
struct padata_instance {
|
|
struct hlist_node node;
|
|
struct workqueue_struct *parallel_wq;
|
|
struct workqueue_struct *serial_wq;
|
|
struct list_head pslist;
|
|
struct padata_cpumask cpumask;
|
|
struct padata_cpumask rcpumask;
|
|
cpumask_var_t omask;
|
|
struct blocking_notifier_head cpumask_change_notifier;
|
|
struct kobject kobj;
|
|
struct mutex lock;
|
|
u8 flags;
|
|
#define PADATA_INIT 1
|
|
#define PADATA_RESET 2
|
|
#define PADATA_INVALID 4
|
|
};
|
|
|
|
extern struct padata_instance *padata_alloc_possible(const char *name);
|
|
extern void padata_free(struct padata_instance *pinst);
|
|
extern struct padata_shell *padata_alloc_shell(struct padata_instance *pinst);
|
|
extern void padata_free_shell(struct padata_shell *ps);
|
|
extern int padata_do_parallel(struct padata_shell *ps,
|
|
struct padata_priv *padata, int *cb_cpu);
|
|
extern void padata_do_serial(struct padata_priv *padata);
|
|
extern int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type,
|
|
cpumask_var_t cpumask);
|
|
extern int padata_start(struct padata_instance *pinst);
|
|
extern void padata_stop(struct padata_instance *pinst);
|
|
extern int padata_register_cpumask_notifier(struct padata_instance *pinst,
|
|
struct notifier_block *nblock);
|
|
extern int padata_unregister_cpumask_notifier(struct padata_instance *pinst,
|
|
struct notifier_block *nblock);
|
|
#endif
|