CVE-2024-40979 in Linux信息

摘要

由 VulDB • 2026-06-01

在 ath12k 驱动中,当固件加载或恢复时,会通过 QMI 消息请求内存段。这些内存段的大小和数量由固件决定,并在 `ath12k_qmi_msg_mem_request_cb()` 中记录到 `ab->qmi.target_mem[]` 数组中。

问题出现在以下流程中:

1. **首次加载固件时**: - 固件请求两个大内存段,大小分别为 7077888 和 8454144。 - 驱动尝试分配这些内存,但分配失败(可能因为内存不足或碎片化)。 - 分配失败后,`ath12k_qmi_free_target_mem_chunk()` 被调用以清理已分配的段。 - 由于第一个段分配失败,其 `v.addr` 为 NULL,因此被跳过。 - 第二个段虽然分配成功,但其实际分配的大小是 524288(由日志中的 `qmi mem seg type 4 size 524288` 可知),而不是固件请求的 8454144。

2. **挂起/恢复时**: - 固件再次请求相同的两个大内存段。 - 驱动再次尝试分配,但同样失败。 - 在清理过程中,驱动尝试释放第二个段,但使用的是固件请求的大小 8454144,而不是实际分配的大小 524288。 - 这导致 `dma_free_coherent()` 被调用时传递了错误的大小,从而引发内核崩溃,因为内核检测到正在释放一块正在使用的内存。

### 根本原因

- **内存分配失败后的清理逻辑不正确**:当分配失败时,驱动没有正确记录实际分配的大小,而是使用了固件请求的大小。 - **内存段大小不一致**:固件请求的大小与实际分配的大小不一致,导致在释放内存时出现错误。

### 解决方案

1. **正确记录实际分配的大小**: - 在分配内存时,记录实际分配的大小,而不是使用固件请求的大小。 - 在释放内存时,使用实际分配的大小。

2. **改进清理逻辑**: - 在分配失败时,确保所有已分配的段都被正确释放,使用实际分配的大小。 - 避免跳过任何已分配的段,即使分配失败,也要确保清理逻辑正确。

3. **增加错误处理**: - 在分配失败时,增加更多的错误处理逻辑,确保不会留下未释放的内存。 - 在释放内存时,增加检查,确保释放的大小与实际分配的大小一致。

### 代码修改建议

```c // 在 ath12k_qmi_msg_mem_request_cb() 中 for (i = 0; i < ab->qmi.mem_seg_count; i++) {
struct ath12k_qmi_mem_seg *seg = &ab->qmi.target_mem[i];
seg->v.addr = dma_alloc_coherent(dev, seg->size, &seg->v.dma_addr, GFP_KERNEL); if (!seg->v.addr) {
// 分配失败,记录实际分配的大小为 0 seg->size = 0; break; } }

// 在 ath12k_qmi_free_target_mem_chunk() 中 for (i = 0; i < ab->qmi.mem_seg_count; i++) {
struct ath12k_qmi_mem_seg *seg = &ab->qmi.target_mem[i];
if (seg->v.addr && seg->size > 0) {
dma_free_coherent(dev, seg->size, seg->v.addr, seg->v.dma_addr); seg->v.addr = NULL; seg->size = 0; } } ```

通过上述修改,可以确保在分配失败时正确记录实际分配的大小,并在释放内存时使用正确的大小,从而避免内核崩溃。

If you want to get best quality of vulnerability data, you may have to visit VulDB.

来源

Are you interested in using VulDB?

Download the whitepaper to learn more about our service!