IPBUF安全漏洞报告
English
CVE-2022-50536 CVSS 7.8 高危

CVE-2022-50536 Linux内核BPF sockmap sock_put()重复调用导致释放后使用漏洞

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

漏洞信息

漏洞编号
CVE-2022-50536
漏洞类型
释放后使用(Use-After-Free)/引用计数错误
CVSS评分
7.8 高危
攻击向量
本地 (AV:L)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Linux内核(bpf, sockmap子系统)

相关标签

Linux内核BPFsockmapUse-After-Free释放后使用引用计数错误内核漏洞权限提升拒绝服务tcp_bpf_send_verdict

漏洞概述

CVE-2022-50536是Linux内核BPF sockmap子系统中存在的一个高危释放后使用(Use-After-Free)漏洞。该漏洞位于内核的tcp_bpf_send_verdict()函数中,具体问题出现在TCP BPF重定向逻辑处理过程中。当通过BPF程序将TCP套接字重定向到另一个套接字时,内核会使用eval变量来跟踪当前的处理状态。在正常流程中,当apply_bytes的数据发送完成后,eval变量会被赋值为__SK_REDIRECT,表示需要将套接字所有权转移。然而,当消息存在more_data(更多数据需要处理)时,内核会进入循环继续处理剩余数据,但eval变量没有被正确重置为__SK_NONE状态。这导致在每次循环迭代中,内核都会错误地认为需要调用sock_put()来释放套接字引用,从而对同一个套接字引用计数执行多次递减操作。当引用计数降至零后,套接字被释放,但代码仍然尝试访问该套接字,最终触发内核级的释放后使用漏洞。该漏洞可被本地低权限用户利用,通过特制的BPF程序触发系统崩溃或权限提升,CVSS评分为7.8,属于高危级别。

技术细节

该漏洞的核心问题在于tcp_bpf_send_verdict()函数中eval变量状态管理的逻辑缺陷。具体技术原理如下:

1. **漏洞触发路径**:在BPF sockmap重定向场景中,当用户态调用sendto()系统调用时,数据流经sock_sendmsg → tcp_bpf_sendmsg → tcp_bpf_send_verdict → tcp_bpf_sendmsg_redir/tcp_bpf_push的调用链。

2. **根本原因**:tcp_bpf_send_verdict()函数中,在处理完一轮apply_bytes数据后,会将eval变量设置为__SK_REDIRECT,表示套接字已被重定向,需要通过sock_put()释放引用。问题在于,当msg->more_data为真时(即还有更多数据待发送),函数进入下一轮循环处理,但没有将eval重置为__SK_NONE,导致在后续循环中再次错误地执行sock_put()。

3. **利用方式**:攻击者需要具备本地低权限访问能力(PR:L),可通过加载特制的BPF程序到sockmap中,然后通过该BPF程序触发TCP重定向路径,构造包含more_data的消息,使内核对同一套接字执行多次sock_put()操作。当引用计数归零后,套接字内存被释放,但内核仍持有该指针并尝试进行TCP传输(如调用__tcp_transmit_skb),从而触发refcount_t饱和警告和use-after-free。

4. **漏洞表现**:内核日志中会出现"refcount_t: addition on 0; use-after-free"警告,以及"Attempt to release TCP socket in state 1"错误信息,最终可能导致系统崩溃(内核panic)或被利用进行权限提升。

攻击链分析

STEP 1
步骤1:环境准备
攻击者需要在受影响的Linux内核版本(6.0之前)上获得本地低权限访问能力,并具备加载BPF程序的权限(CAP_BPF/CAP_NET_ADMIN)或利用其他提权手段获取该权限。
STEP 2
步骤2:加载恶意BPF程序
攻击者编写并加载特制的BPF程序到sockmap中,该程序配置为对特定TCP套接字进行重定向(redirect)操作,将数据流从一个套接字转发到另一个套接字。
STEP 3
步骤3:触发more_data路径
攻击者通过BPF附加的TCP套接字发送大量数据(大于apply_bytes阈值),使内核在tcp_bpf_send_verdict()中进入msg->more_data循环处理路径。
STEP 4
步骤4:触发重复sock_put()
由于eval变量未被重置为__SK_NONE,内核在每次循环迭代中都错误地执行sock_put(),导致目标套接字的引用计数被多次递减直至归零,触发refcount_t饱和警告。
STEP 5
步骤5:利用释放后使用
套接字被释放后,内核仍持有该指针并尝试执行TCP传输操作(如__tcp_transmit_skb),触发use-after-free。攻击者可利用此漏洞实现权限提升或拒绝服务攻击(系统崩溃)。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
/* CVE-2022-50536 - Linux kernel BPF sockmap Use-After-Free PoC * This PoC demonstrates triggering the repeated sock_put() bug * by sending data through a BPF-attached TCP socket with more_data. * * Note: Requires CAP_BPF/CAP_NET_ADMIN or root, and a kernel < 6.0 affected by the bug. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <errno.h> #define SERVER_PORT 9090 #define BUF_SIZE 65536 #define NUM_ITERATIONS 100 int main(int argc, char *argv[]) { int srv_fd, cli_fd; struct sockaddr_in addr; char buf[BUF_SIZE]; /* Create server socket */ srv_fd = socket(AF_INET, SOCK_STREAM, 0); if (srv_fd < 0) { perror("socket"); return 1; } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr.sin_port = htons(SERVER_PORT); if (bind(srv_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); return 1; } listen(srv_fd, 1); /* Fork to create client */ if (fork() == 0) { /* Client: connect and send large data to trigger more_data path */ close(srv_fd); cli_fd = socket(AF_INET, SOCK_STREAM, 0); usleep(100000); connect(cli_fd, (struct sockaddr *)&addr, sizeof(addr)); memset(buf, 'A', BUF_SIZE); /* Send multiple large chunks to trigger msg->more_data in tcp_bpf_send_verdict */ for (int i = 0; i < NUM_ITERATIONS; i++) { if (send(cli_fd, buf, BUF_SIZE, 0) < 0) { perror("send"); break; } } close(cli_fd); return 0; } /* Server: accept connection */ socklen_t len = sizeof(addr); cli_fd = accept(srv_fd, (struct sockaddr *)&addr, &len); if (cli_fd < 0) { perror("accept"); return 1; } /* Receive data - this triggers the BPF sockmap redirect path */ while (recv(cli_fd, buf, BUF_SIZE, 0) > 0) ; close(cli_fd); close(srv_fd); printf("PoC completed. Check dmesg for refcount warnings.\n"); return 0; }

影响范围

Linux kernel < 6.0(受bpf sockmap漏洞影响的所有版本)
Linux kernel 5.15.x(5.15稳定分支受影响版本)
Linux kernel 5.10.x(5.10稳定分支受影响版本)
Linux kernel 5.4.x(5.4稳定分支受影响版本)
Linux kernel 4.19.x(4.19稳定分支受影响版本)

防御指南

临时缓解措施
在无法立即升级内核的情况下,建议采取以下临时缓解措施:1)通过设置内核参数`kernel.unprivileged_bpf_disabled=1`禁止非特权用户加载BPF程序;2)使用Linux安全模块(如SELinux、AppArmor)限制普通用户对BPF相关系统调用的访问;3)监控`dmesg`日志,及时发现refcount_t饱和警告和TCP套接字状态异常;4)限制本地用户对BPF相关设备文件(如/dev/bpf)的访问权限;5)对于多用户系统,考虑将BPF功能限制在特权用户范围内使用。

参考链接

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