CVE-2021-20226:详解 Linux 内核 IO_URING 子系统中的引用计数漏洞
编译:奇安信代码卫士
Linux 内核 5.1 引入一个新的异步 I/O 功能,名为 “io_uring”。该子系统通过批量进行 I/O 操作系统调用进行操作,因此多个 I/O 操作可在一个系统调用中执行。
Linux 内核 5.6 中的IORING_OP_CLOSE 操作实现中存在缺陷。当系统调用向内核线程传递 files_strut 时,io_grab_files() 并不会增加代码注释中所标注 (1) 处的引用基数,从而导致后续被释放的文件结构遭访问。
static int io_grab_files(struct io_kiocb *req)
{
// ...
rcu_read_lock();
spin_lock_irq(&ctx->inflight_lock);spin_lock_irq(&ctx->inflight_lock);
if (fcheck(ctx->ring_fd) == ctx->ring_file) {
list_add(&req->inflight_entry, &ctx->inflight_list);
req->flags |= REQ_F_INFLIGHT;
req->work.files = current->files; // <-- (1)
ret = 0;
}
spin_unlock_irq(&ctx->inflight_lock);
rcu_read_unlock();
return ret;
}
map_lookup_elem() 和 map_update_elem() 函数可用于利用该漏洞。
static int map_lookup_elem(union bpf_attr *attr)
{
void __user *ukey = u64_to_user_ptr(attr->key);
int ufd = attr->map_fd;
// ...
f = fdget(ufd); // <-- (2)
map = __bpf_map_get(f);
// ...
key = __bpf_copy_key(ukey, map->key_size); key = __bpf_copy_key(ukey, map->key_size); // <-- (3)
if (IS_ERR(key)) {
err = PTR_ERR(key);
goto err_put;
}
value_size = bpf_map_value_size(map); // <-- (4)
err = -ENOMEM;
value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
if (!value)
goto free_key;
err = bpf_map_copy_value(map, key, value, attr->flags); // <-- (5)
if (err)
goto free_value;
err = -EFAULT;
if (copy_to_user(uvalue, value, value_size) != 0) // <-- (6)
goto free_value;
// ...
}
注释中 (2) 处的 fdget() 是一个优化后的函数,如果当前任务是 single-thread,则不会增加引用计数。返回的 file 结构 f 可由后续的 IORING_OP_CLOSE 释放。注释 (3) 处的 _bpf_copy_key() 系统调用实际上是 copy_from_user() 的封装。这就使得我们能够使用 userfaultfd 生成竞争条件并触发该漏洞。此时,文件结构 f 及其对应的 map 被释放。可通过 (4) 和 (5) 处的虚假数据对 map 内存进行重新分配。最终,我们可以读取 (6) 处的任意内存并披露用户模式。
利用时间轴如下:
函数 recvmsg() 用于定时控制。通过喷射 setxattr() 即可伪造被释放的 bpf_map。通过 map_update_elem() 即可实现任意写。由于 fdget() 条件的存在,该利用方法仅限于单核环境。
新功能意味着新的攻击面,而新的攻击面通常会导致新漏洞的产生。有兴趣的读者可以看看从这个子系统中是否会找到其它漏洞。无论如何,Ryota 的这份漏洞报告十分出色。Ryota 正是在2021年 Pwn2Own 大赛中凭借演示 Ubuntu 中另外一个提权漏洞而获得3万美元赏金的研究员。让我们一起期待他再创佳绩吧!
三个已存在15年的 Linux 内核漏洞
Linux 内核修复5个高危漏洞
攻击者可提前检测到 Linux 内核的补丁并开发 exploit
https://www.zerodayinitiative.com/blog/2021/4/22/cve-2021-20226-a-reference-counting-bug-in-the-linux-kernel-iouring-subsystem
题图:Pixabay License
本文由奇安信编译,不代表奇安信观点。转载请注明“转自奇安信代码卫士 https://codesafe.qianxin.com”。
奇安信代码卫士 (codesafe)
国内首个专注于软件开发安全的
产品线。