CVE-2025-37772
Severity CVSS v4.0:
Pending analysis
Type:
Unavailable / Other
Publication date:
01/05/2025
Last modified:
02/05/2025
Description
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
RDMA/cma: Fix workqueue crash in cma_netevent_work_handler<br />
<br />
struct rdma_cm_id has member "struct work_struct net_work"<br />
that is reused for enqueuing cma_netevent_work_handler()s<br />
onto cma_wq.<br />
<br />
Below crash[1] can occur if more than one call to<br />
cma_netevent_callback() occurs in quick succession,<br />
which further enqueues cma_netevent_work_handler()s for the<br />
same rdma_cm_id, overwriting any previously queued work-item(s)<br />
that was just scheduled to run i.e. there is no guarantee<br />
the queued work item may run between two successive calls<br />
to cma_netevent_callback() and the 2nd INIT_WORK would overwrite<br />
the 1st work item (for the same rdma_cm_id), despite grabbing<br />
id_table_lock during enqueue.<br />
<br />
Also drgn analysis [2] indicates the work item was likely overwritten.<br />
<br />
Fix this by moving the INIT_WORK() to __rdma_create_id(),<br />
so that it doesn&#39;t race with any existing queue_work() or<br />
its worker thread.<br />
<br />
[1] Trimmed crash stack:<br />
=============================================<br />
BUG: kernel NULL pointer dereference, address: 0000000000000008<br />
kworker/u256:6 ... 6.12.0-0...<br />
Workqueue: cma_netevent_work_handler [rdma_cm] (rdma_cm)<br />
RIP: 0010:process_one_work+0xba/0x31a<br />
Call Trace:<br />
worker_thread+0x266/0x3a0<br />
kthread+0xcf/0x100<br />
ret_from_fork+0x31/0x50<br />
ret_from_fork_asm+0x1a/0x30<br />
=============================================<br />
<br />
[2] drgn crash analysis:<br />
<br />
>>> trace = prog.crashed_thread().stack_trace()<br />
>>> trace<br />
(0) crash_setup_regs (./arch/x86/include/asm/kexec.h:111:15)<br />
(1) __crash_kexec (kernel/crash_core.c:122:4)<br />
(2) panic (kernel/panic.c:399:3)<br />
(3) oops_end (arch/x86/kernel/dumpstack.c:382:3)<br />
...<br />
(8) process_one_work (kernel/workqueue.c:3168:2)<br />
(9) process_scheduled_works (kernel/workqueue.c:3310:3)<br />
(10) worker_thread (kernel/workqueue.c:3391:4)<br />
(11) kthread (kernel/kthread.c:389:9)<br />
<br />
Line workqueue.c:3168 for this kernel version is in process_one_work():<br />
3168 strscpy(worker->desc, pwq->wq->name, WORKER_DESC_LEN);<br />
<br />
>>> trace[8]["work"]<br />
*(struct work_struct *)0xffff92577d0a21d8 = {<br />
.data = (atomic_long_t){<br />
.counter = (s64)536870912, >> trace[8]["pwq"]<br />
(struct pool_workqueue *)<br />
<br />
In process_one_work(), pwq is assigned from:<br />
struct pool_workqueue *pwq = get_work_pwq(work);<br />
<br />
and get_work_pwq() is:<br />
static struct pool_workqueue *get_work_pwq(struct work_struct *work)<br />
{<br />
unsigned long data = atomic_long_read(&work->data);<br />
<br />
if (data & WORK_STRUCT_PWQ)<br />
return work_struct_pwq(data);<br />
else<br />
return NULL;<br />
}<br />
<br />
WORK_STRUCT_PWQ is 0x4:<br />
>>> print(repr(prog[&#39;WORK_STRUCT_PWQ&#39;]))<br />
Object(prog, &#39;enum work_flags&#39;, value=4)<br />
<br />
But work->data is 536870912 which is 0x20000000.<br />
So, get_work_pwq() returns NULL and we crash in process_one_work():<br />
3168 strscpy(worker->desc, pwq->wq->name, WORKER_DESC_LEN);<br />
=============================================
Impact
References to Advisories, Solutions, and Tools
- https://git.kernel.org/stable/c/45f5dcdd049719fb999393b30679605f16ebce14
- https://git.kernel.org/stable/c/51003b2c872c63d28bcf5fbcc52cf7b05615f7b7
- https://git.kernel.org/stable/c/b172a4a0de254f1fcce7591833a9a63547c2f447
- https://git.kernel.org/stable/c/c2b169fc7a12665d8a675c1ff14bca1b9c63fb9a
- https://git.kernel.org/stable/c/d23fd7a539ac078df119707110686a5b226ee3bb