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&amp;#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 /> &gt;&gt;&gt; trace = prog.crashed_thread().stack_trace()<br /> &gt;&gt;&gt; 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-&gt;desc, pwq-&gt;wq-&gt;name, WORKER_DESC_LEN);<br /> <br /> &gt;&gt;&gt; trace[8]["work"]<br /> *(struct work_struct *)0xffff92577d0a21d8 = {<br /> .data = (atomic_long_t){<br /> .counter = (s64)536870912, &gt;&gt; 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(&amp;work-&gt;data);<br /> <br /> if (data &amp; WORK_STRUCT_PWQ)<br /> return work_struct_pwq(data);<br /> else<br /> return NULL;<br /> }<br /> <br /> WORK_STRUCT_PWQ is 0x4:<br /> &gt;&gt;&gt; print(repr(prog[&amp;#39;WORK_STRUCT_PWQ&amp;#39;]))<br /> Object(prog, &amp;#39;enum work_flags&amp;#39;, value=4)<br /> <br /> But work-&gt;data is 536870912 which is 0x20000000.<br /> So, get_work_pwq() returns NULL and we crash in process_one_work():<br /> 3168 strscpy(worker-&gt;desc, pwq-&gt;wq-&gt;name, WORKER_DESC_LEN);<br /> =============================================

Impact