Security Vulnerability Report
中文
CVE-2025-39945 CVSS 7.8 HIGH

CVE-2025-39945

Published: 2025-10-04 08:15:48
Last Modified: 2026-01-23 20:56:33
Source: 416baaa9-dc9f-4396-8d5f-8c081fb06d67

Description

In the Linux kernel, the following vulnerability has been resolved: cnic: Fix use-after-free bugs in cnic_delete_task The original code uses cancel_delayed_work() in cnic_cm_stop_bnx2x_hw(), which does not guarantee that the delayed work item 'delete_task' has fully completed if it was already running. Additionally, the delayed work item is cyclic, the flush_workqueue() in cnic_cm_stop_bnx2x_hw() only blocks and waits for work items that were already queued to the workqueue prior to its invocation. Any work items submitted after flush_workqueue() is called are not included in the set of tasks that the flush operation awaits. This means that after the cyclic work items have finished executing, a delayed work item may still exist in the workqueue. This leads to use-after-free scenarios where the cnic_dev is deallocated by cnic_free_dev(), while delete_task remains active and attempt to dereference cnic_dev in cnic_delete_task(). A typical race condition is illustrated below: CPU 0 (cleanup) | CPU 1 (delayed work callback) cnic_netdev_event() | cnic_stop_hw() | cnic_delete_task() cnic_cm_stop_bnx2x_hw() | ... cancel_delayed_work() | /* the queue_delayed_work() flush_workqueue() | executes after flush_workqueue()*/ | queue_delayed_work() cnic_free_dev(dev)//free | cnic_delete_task() //new instance | dev = cp->dev; //use Replace cancel_delayed_work() with cancel_delayed_work_sync() to ensure that the cyclic delayed work item is properly canceled and that any ongoing execution of the work item completes before the cnic_dev is deallocated. Furthermore, since cancel_delayed_work_sync() uses __flush_work(work, true) to synchronously wait for any currently executing instance of the work item to finish, the flush_workqueue() becomes redundant and should be removed. This bug was identified through static analysis. To reproduce the issue and validate the fix, I simulated the cnic PCI device in QEMU and introduced intentional delays — such as inserting calls to ssleep() within the cnic_delete_task() function — to increase the likelihood of triggering the bug.

CVSS Details

CVSS Score
7.8
Severity
HIGH
CVSS Vector
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Configurations (Affected Products)

cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* - VULNERABLE
Linux Kernel < 6.17(包含cnic驱动的所有受影响版本)

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
// CVE-2025-39945 PoC - Use-After-Free in cnic_delete_task // This PoC demonstrates the race condition that triggers the UAF bug. // The vulnerability was identified through static analysis and validated // using QEMU with simulated cnic PCI device. #include <linux/module.h> #include <linux/kernel.h> #include <linux/workqueue.h> #include <linux/delay.h> #include <linux/slab.h> // Simulated cnic_dev structure struct cnic_dev { int ref_count; char data[64]; }; static struct cnic_dev *global_dev; static struct delayed_work delete_task; static struct workqueue_struct *cnic_wq; // Simulated cnic_delete_task callback - vulnerable function static void cnic_delete_task_fn(struct work_struct *work) { struct cnic_dev *dev = global_dev; // Intentional delay to increase likelihood of triggering the race // In real kernel code, this represents cnic_delete_task() accessing // cnic_dev fields after it has been freed ssleep(2); if (dev) { // Use-after-free: dev may have been freed by cnic_free_dev() printk(KERN_INFO "Accessing dev->data: %s\n", dev->data); dev->ref_count++; } } // Simulated cnic_cm_stop_bnx2x_hw - vulnerable cleanup path static void cnic_cm_stop_bnx2x_hw(void) { // BUG: cancel_delayed_work() does not wait for running work cancel_delayed_work(&delete_task); // BUG: flush_workqueue() does not wait for work queued after this call flush_workqueue(cnic_wq); } // Simulated cnic_free_dev static void cnic_free_dev(struct cnic_dev *dev) { kfree(dev); global_dev = NULL; } // Trigger the race condition static int __init trigger_uaf_init(void) { cnic_wq = create_singlethread_workqueue("cnic_wq"); global_dev = kmalloc(sizeof(struct cnic_dev), GFP_KERNEL); global_dev->ref_count = 0; strcpy(global_dev->data, "cnic_dev_data"); // Queue initial delayed work INIT_DELAYED_WORK(&delete_task, cnic_delete_task_fn); queue_delayed_work(cnic_wq, &delete_task, msecs_to_jiffies(100)); // Simulate cleanup path - this is where the race occurs cnic_cm_stop_bnx2x_hw(); // After flush_workqueue(), a new delayed work may still be queued // by the running cnic_delete_task_fn queue_delayed_work(cnic_wq, &delete_task, msecs_to_jiffies(100)); // Free dev while delete_task may still be active -> UAF cnic_free_dev(global_dev); return 0; } module_init(trigger_uaf_init); MODULE_LICENSE("GPL");

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2025-39945", "sourceIdentifier": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "published": "2025-10-04T08:15:47.613", "lastModified": "2026-01-23T20:56:32.720", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "In the Linux kernel, the following vulnerability has been resolved:\n\ncnic: Fix use-after-free bugs in cnic_delete_task\n\nThe original code uses cancel_delayed_work() in cnic_cm_stop_bnx2x_hw(),\nwhich does not guarantee that the delayed work item 'delete_task' has\nfully completed if it was already running. Additionally, the delayed work\nitem is cyclic, the flush_workqueue() in cnic_cm_stop_bnx2x_hw() only\nblocks and waits for work items that were already queued to the\nworkqueue prior to its invocation. Any work items submitted after\nflush_workqueue() is called are not included in the set of tasks that the\nflush operation awaits. This means that after the cyclic work items have\nfinished executing, a delayed work item may still exist in the workqueue.\nThis leads to use-after-free scenarios where the cnic_dev is deallocated\nby cnic_free_dev(), while delete_task remains active and attempt to\ndereference cnic_dev in cnic_delete_task().\n\nA typical race condition is illustrated below:\n\nCPU 0 (cleanup) | CPU 1 (delayed work callback)\ncnic_netdev_event() |\n cnic_stop_hw() | cnic_delete_task()\n cnic_cm_stop_bnx2x_hw() | ...\n cancel_delayed_work() | /* the queue_delayed_work()\n flush_workqueue() | executes after flush_workqueue()*/\n | queue_delayed_work()\n cnic_free_dev(dev)//free | cnic_delete_task() //new instance\n | dev = cp->dev; //use\n\nReplace cancel_delayed_work() with cancel_delayed_work_sync() to ensure\nthat the cyclic delayed work item is properly canceled and that any\nongoing execution of the work item completes before the cnic_dev is\ndeallocated. Furthermore, since cancel_delayed_work_sync() uses\n__flush_work(work, true) to synchronously wait for any currently\nexecuting instance of the work item to finish, the flush_workqueue()\nbecomes redundant and should be removed.\n\nThis bug was identified through static analysis. To reproduce the issue\nand validate the fix, I simulated the cnic PCI device in QEMU and\nintroduced intentional delays — such as inserting calls to ssleep()\nwithin the cnic_delete_task() function — to increase the likelihood\nof triggering the bug."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "baseScore": 7.8, "baseSeverity": "HIGH", "attackVector": "LOCAL", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH"}, "exploitabilityScore": 1.8, "impactScore": 5.9}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-416"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "2.6.37", "versionEndExcluding": "5.4.300", "matchCriteriaId": "7175A0F5-9125-4D84-A39A-3FA75A464894"}, {"vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "5.5", "versionEndExcluding": "5.10.245", "matchCriteriaId": "B0E443AF-02FC-45A1-9CD7-3F80A65F1A15"}, {"vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "5.11", "versionEndExcluding": "5.15.194", "matchCriteriaId": "CF862263-DC8D-4324-A52A-DA1D7880B35A"}, {"vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "5.16", "versionEndExcluding": "6.1.154", "matchCriteriaId": "E49CD91E-FC55-45B0-BB63-9AD5F5D70CAA"}, {"vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "6.2", "versionEndExcluding": "6.6.108", "matchCriteriaId": "A7E8EAEE-7731-4996-9578-696255D61EA2"}, {"vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "6.7", "versionEndExcluding": "6.12.49", "matchCriteriaId": "CAA033E9-A2C5-4976-A83E-9804D8FB827F"}, {"vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "6.13", "versionEndExcluding": "6.16.9", "matchCriteriaId": "638DD910-1189-4F5E-98BF-2D436B695112"}, {"vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:6.17:rc1:*:*:*:*:*:*", "matchCriteriaId": "327D22EF-390B-454C-BD31-2ED23C998A1C"}, {"vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:6.17:rc2:*:*:*:*:*:*", "matchCriteriaId": "C730CD9A-D969-4A8E-9522-162AAF7C0EE9"}, {"vulnerable": true, "criteria": "cpe:2.3:o:linux:linu ... (truncated)