Skip to content

Commit 13a3d44

Browse files
author
CKI KWF Bot
committed
Merge: padata: Fix pd UAF once and for all
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/7356 JIRA: https://issues.redhat.com/browse/RHEL-39495 Upstream Status: v6.17 commit 71203f6 Author: Herbert Xu <herbert@gondor.apana.org.au> Date: Sat May 24 20:32:20 2025 +0800 padata: Fix pd UAF once and for all There is a race condition/UAF in padata_reorder that goes back to the initial commit. A reference count is taken at the start of the process in padata_do_parallel, and released at the end in padata_serial_worker. This reference count is (and only is) required for padata_replace to function correctly. If padata_replace is never called then there is no issue. In the function padata_reorder which serves as the core of padata, as soon as padata is added to queue->serial.list, and the associated spin lock released, that padata may be processed and the reference count on pd would go away. Fix this by getting the next padata before the squeue->serial lock is released. In order to make this possible, simplify padata_reorder by only calling it once the next padata arrives. Fixes: 16295be ("padata: Generic parallelization/serialization interface") Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Herbert Xu <herbert.xu@redhat.com> Approved-by: Rafael Aquini <raquini@redhat.com> Approved-by: Herton R. Krzesinski <herton@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
2 parents e1b834f + 420feab commit 13a3d44

File tree

2 files changed

+41
-98
lines changed

2 files changed

+41
-98
lines changed

include/linux/padata.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,6 @@ struct padata_cpumask {
9090
* @processed: Number of already processed objects.
9191
* @cpu: Next CPU to be processed.
9292
* @cpumask: The cpumasks in use for parallel and serial workers.
93-
* @reorder_work: work struct for reordering.
94-
* @lock: Reorder lock.
9593
*/
9694
struct parallel_data {
9795
struct padata_shell *ps;
@@ -102,8 +100,6 @@ struct parallel_data {
102100
unsigned int processed;
103101
int cpu;
104102
struct padata_cpumask cpumask;
105-
struct work_struct reorder_work;
106-
spinlock_t ____cacheline_aligned lock;
107103
};
108104

109105
/**

kernel/padata.c

Lines changed: 41 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -261,117 +261,74 @@ EXPORT_SYMBOL(padata_do_parallel);
261261
* be parallel processed by another cpu and is not yet present in
262262
* the cpu's reorder queue.
263263
*/
264-
static struct padata_priv *padata_find_next(struct parallel_data *pd,
265-
bool remove_object)
264+
static struct padata_priv *padata_find_next(struct parallel_data *pd, int cpu,
265+
unsigned int processed)
266266
{
267267
struct padata_priv *padata;
268268
struct padata_list *reorder;
269-
int cpu = pd->cpu;
270269

271270
reorder = per_cpu_ptr(pd->reorder_list, cpu);
272271

273272
spin_lock(&reorder->lock);
274-
if (list_empty(&reorder->list)) {
275-
spin_unlock(&reorder->lock);
276-
return NULL;
277-
}
273+
if (list_empty(&reorder->list))
274+
goto notfound;
278275

279276
padata = list_entry(reorder->list.next, struct padata_priv, list);
280277

281278
/*
282279
* Checks the rare case where two or more parallel jobs have hashed to
283280
* the same CPU and one of the later ones finishes first.
284281
*/
285-
if (padata->seq_nr != pd->processed) {
286-
spin_unlock(&reorder->lock);
287-
return NULL;
288-
}
289-
290-
if (remove_object) {
291-
list_del_init(&padata->list);
292-
++pd->processed;
293-
pd->cpu = cpumask_next_wrap(cpu, pd->cpumask.pcpu, -1, false);
294-
}
282+
if (padata->seq_nr != processed)
283+
goto notfound;
295284

285+
list_del_init(&padata->list);
296286
spin_unlock(&reorder->lock);
297287
return padata;
288+
289+
notfound:
290+
pd->processed = processed;
291+
pd->cpu = cpu;
292+
spin_unlock(&reorder->lock);
293+
return NULL;
298294
}
299295

300-
static void padata_reorder(struct parallel_data *pd)
296+
static void padata_reorder(struct padata_priv *padata)
301297
{
298+
struct parallel_data *pd = padata->pd;
302299
struct padata_instance *pinst = pd->ps->pinst;
303-
int cb_cpu;
304-
struct padata_priv *padata;
305-
struct padata_serial_queue *squeue;
306-
struct padata_list *reorder;
300+
unsigned int processed;
301+
int cpu;
307302

308-
/*
309-
* We need to ensure that only one cpu can work on dequeueing of
310-
* the reorder queue the time. Calculating in which percpu reorder
311-
* queue the next object will arrive takes some time. A spinlock
312-
* would be highly contended. Also it is not clear in which order
313-
* the objects arrive to the reorder queues. So a cpu could wait to
314-
* get the lock just to notice that there is nothing to do at the
315-
* moment. Therefore we use a trylock and let the holder of the lock
316-
* care for all the objects enqueued during the holdtime of the lock.
317-
*/
318-
if (!spin_trylock_bh(&pd->lock))
319-
return;
303+
processed = pd->processed;
304+
cpu = pd->cpu;
320305

321-
while (1) {
322-
padata = padata_find_next(pd, true);
306+
do {
307+
struct padata_serial_queue *squeue;
308+
int cb_cpu;
323309

324-
/*
325-
* If the next object that needs serialization is parallel
326-
* processed by another cpu and is still on it's way to the
327-
* cpu's reorder queue, nothing to do for now.
328-
*/
329-
if (!padata)
330-
break;
310+
processed++;
311+
/* When sequence wraps around, reset to the first CPU. */
312+
if (unlikely(processed == 0))
313+
cpu = cpumask_first(pd->cpumask.pcpu);
314+
else
315+
cpu = cpumask_next_wrap(cpu, pd->cpumask.pcpu, -1, false);
331316

332317
cb_cpu = padata->cb_cpu;
333318
squeue = per_cpu_ptr(pd->squeue, cb_cpu);
334319

335320
spin_lock(&squeue->serial.lock);
336321
list_add_tail(&padata->list, &squeue->serial.list);
337-
spin_unlock(&squeue->serial.lock);
338-
339322
queue_work_on(cb_cpu, pinst->serial_wq, &squeue->work);
340-
}
341323

342-
spin_unlock_bh(&pd->lock);
343-
344-
/*
345-
* The next object that needs serialization might have arrived to
346-
* the reorder queues in the meantime.
347-
*
348-
* Ensure reorder queue is read after pd->lock is dropped so we see
349-
* new objects from another task in padata_do_serial. Pairs with
350-
* smp_mb in padata_do_serial.
351-
*/
352-
smp_mb();
353-
354-
reorder = per_cpu_ptr(pd->reorder_list, pd->cpu);
355-
if (!list_empty(&reorder->list) && padata_find_next(pd, false)) {
356324
/*
357-
* Other context(eg. the padata_serial_worker) can finish the request.
358-
* To avoid UAF issue, add pd ref here, and put pd ref after reorder_work finish.
325+
* If the next object that needs serialization is parallel
326+
* processed by another cpu and is still on it's way to the
327+
* cpu's reorder queue, end the loop.
359328
*/
360-
padata_get_pd(pd);
361-
queue_work(pinst->serial_wq, &pd->reorder_work);
362-
}
363-
}
364-
365-
static void invoke_padata_reorder(struct work_struct *work)
366-
{
367-
struct parallel_data *pd;
368-
369-
local_bh_disable();
370-
pd = container_of(work, struct parallel_data, reorder_work);
371-
padata_reorder(pd);
372-
local_bh_enable();
373-
/* Pairs with putting the reorder_work in the serial_wq */
374-
padata_put_pd(pd);
329+
padata = padata_find_next(pd, cpu, processed);
330+
spin_unlock(&squeue->serial.lock);
331+
} while (padata);
375332
}
376333

377334
static void padata_serial_worker(struct work_struct *serial_work)
@@ -422,6 +379,7 @@ void padata_do_serial(struct padata_priv *padata)
422379
struct padata_list *reorder = per_cpu_ptr(pd->reorder_list, hashed_cpu);
423380
struct padata_priv *cur;
424381
struct list_head *pos;
382+
bool gotit = true;
425383

426384
spin_lock(&reorder->lock);
427385
/* Sort in ascending order of sequence number. */
@@ -431,17 +389,14 @@ void padata_do_serial(struct padata_priv *padata)
431389
if ((signed int)(cur->seq_nr - padata->seq_nr) < 0)
432390
break;
433391
}
434-
list_add(&padata->list, pos);
392+
if (padata->seq_nr != pd->processed) {
393+
gotit = false;
394+
list_add(&padata->list, pos);
395+
}
435396
spin_unlock(&reorder->lock);
436397

437-
/*
438-
* Ensure the addition to the reorder list is ordered correctly
439-
* with the trylock of pd->lock in padata_reorder. Pairs with smp_mb
440-
* in padata_reorder.
441-
*/
442-
smp_mb();
443-
444-
padata_reorder(pd);
398+
if (gotit)
399+
padata_reorder(padata);
445400
}
446401
EXPORT_SYMBOL(padata_do_serial);
447402

@@ -631,9 +586,7 @@ static struct parallel_data *padata_alloc_pd(struct padata_shell *ps)
631586
padata_init_squeues(pd);
632587
pd->seq_nr = -1;
633588
refcount_set(&pd->refcnt, 1);
634-
spin_lock_init(&pd->lock);
635589
pd->cpu = cpumask_first(pd->cpumask.pcpu);
636-
INIT_WORK(&pd->reorder_work, invoke_padata_reorder);
637590

638591
return pd;
639592

@@ -1143,12 +1096,6 @@ void padata_free_shell(struct padata_shell *ps)
11431096
if (!ps)
11441097
return;
11451098

1146-
/*
1147-
* Wait for all _do_serial calls to finish to avoid touching
1148-
* freed pd's and ps's.
1149-
*/
1150-
synchronize_rcu();
1151-
11521099
mutex_lock(&ps->pinst->lock);
11531100
list_del(&ps->list);
11541101
pd = rcu_dereference_protected(ps->pd, 1);

0 commit comments

Comments
 (0)