✨ 要点🔬 技术摘要
想象一下,Linux 操作系统是一座规模宏大、繁忙喧嚣的城市。在这座城市内部,有成千上万个专门的店铺(称为驱动程序 ),它们控制着从你的鼠标、键盘到硬盘和网卡的一切。
为了在这些店铺中完成任何事情,你(用户)必须向店员递交一张特定的票据 。这张票据是一个被称为 IOCTL 命令 的数字。如果你递交了正确的票据,店员就会打开门并按照你的要求办事。如果你递交了错误的票据,或者票据中隐藏了陷阱,店员可能会不小心损坏店铺、窃取数据,或者让陌生人溜进来。
问题在于,这些票据并没有一个中央电话簿。每个店员都发明了自己的票据,编写了自己的规则,并将它们保存在各自的后勤办公室里。安全专家试图寻找薄弱环节时,不得不逐一敲开每一扇门,希望能遇到一位忘记检查票据有效性的店员。
本论文介绍了一种针对这些票据的“城市人口普查”。
以下是作者如何构建这个普查系统以及他们发现了什么,使用了简单的类比:
1. 大地图(人口普查)
作者并没有通过逐一敲门来工作,而是制造了一个机器人来阅读整个城市的蓝图 (源代码)。
过程: 他们编译了一份清单,列出了在标准城市布局中营业的所有店铺(878 个模块)。
结果: 他们创建了一个巨大的、可搜索的数据库,其中包含:
586 个票据分发员: 接待你的主要前台人员。
1,289 个解码票据: 他们弄清楚了 1,289 个不同票据数字的具体含义(例如,“检查状态”、“写入数据”)。
3,583 个危险开口: 他们发现了某些地方,店员在接收你的票据后,在没有检查其是否安全的情况下就立即采取行动(就像一个店员在检查你的身份证之前,就让你触摸商品一样)。
2. “VIP 过滤器”(威胁模型)
并非所有的店铺都向公众开放。有些店铺只对市长(系统管理员)或警察(安全模块)开放。
问题: 如果一家店被“仅限市长”的闸门锁住了,普通公民就进不去,因此对于日常黑客来说,这方面的风险较小。
解决方案: 作者在他们的地图中添加了一个过滤器。他们问道:“是否存在一个硬性锁(能力门控/capability gate)可以阻止普通人进入?”
结果: 他们过滤掉了 50 家严格管控的店铺。这留下了 281 家 可能对普通人开放的店铺。这并不保证任何人都能进去,但这是“最坏情况”下的清单,即那些可能 可以触达的地方。
3. “安全检查”(净化/Sanitization)
作者观察了这 281 家潜在开放的店铺,看看店员是否足够谨慎。
启发式方法: 他们寻找一种特定的模式:店员是否在让用户接触敏感内容之前 ,先检查了票据的大小?
发现: 他们发现了 3,201 个店员似乎跳过了此项检查的地方。
免责声明: 作者对此很诚实。他们称这是一种“代理”(proxy)或“最佳猜测”。这就像看到店员瞥了一眼票据,就假设他们已经检查过了,而没有实际观察他们进行数学运算的过程。这是一个关于有多少地方可能 存在风险的上限定,而不是一份确认已损坏店铺的名单。
4. 测试地图(回测)
为了验证其地图的准确性,作者选取了近期在城市中发现的 22 个已知安全漏洞 (CVEs),并检查了他们的地图是否显示了这些漏洞。
成功之处: 他们的地图找到了其中 7 个漏洞的位置。
遗漏之处: 他们漏掉了 15 个。为什么?因为那 15 个漏洞位于未使用标准“票据柜台”系统的店铺中。它们使用了秘密侧门或其他的交付方式,而机器人的程序尚未涵盖这些方式。
教训: 该地图在寻找标准票据柜台方面非常出色,但它需要学习关于“秘密侧门”(如显卡或视频驱动程序使用的侧门)的知识,才能变得完整。
5. 为什么这很重要
它是静态列表: 不同于其他尝试通过运行并使系统崩溃来破坏城市的工具(动态测试),这个工具只是阅读蓝图。它发现了危险的“形状”,即使目前还没有人尝试入侵那里。
它是可搜索的: 安全研究人员现在可以提出问题,例如:“显示所有使用‘看门狗’(Watchdog)票据且没有锁的店铺。”他们不必再手动阅读数千页的代码。
它是开放的: 作者发布了地图的“结构化”部分(店铺和票据的列表)供所有人使用,但他们将“针对性”部分(即具体的、最危险且未经验证的漏洞列表)保持私密,以防止恶意行为者立即利用它。
总结
作者为 Linux 内核的控制按钮构建了一个可搜索的清单 。他们绘制了数千个命令的地图,过滤掉了那些被“仅限管理员”闸门锁住的部分,并强调了那些看起来可能缺少安全检查的部分。这并不是一份确认存在的 Bug 清单,而是一张庞大且有组织的地图,它告诉安全专家应该首先去哪里寻找它们。
技术摘要:Linux IOCTL 普查
问题陈述 ioctl 系统调用是 Linux 最主要的设备控制接口,允许用户态程序向内核驱动程序发送数值命令码和参数缓冲区。虽然这对于硬件配置和状态管理至关重要,但该接口也代表了一个庞大、异构且缺乏系统编目的本地攻击面。驱动程序定义了数以千计的独特命令,且通常在内核上下文中解析参数,而缺乏统一的校验机制。一个信任未经校验的参数长度的处理函数可能会导致越界内存读或写。
目前的分析方法是碎片化的:
动态扫描器(如 syzkaller): 有效于发现运行时漏洞和竞态条件,但受限于其被明确告知需要执行的特定命令空间。它们报告触发的漏洞,而非未探索的命令空间。
人工整理: 诸如非特权可达性(unprivileged-reach)LPE 目录和威胁模型文档等资源存在,但它们是手工维护的散文式记录,而非对解码后的命令空间进行系统性的、可查询的枚举。
目前缺乏一个持久的、源自源码的清单,能够映射整个静态命令表面,包括调度器(dispatchers)、解码后的命令、处理函数以及权限门禁(permission gates)。
方法论:提取-过滤-排序 (Extract-Gate-Rank) 作者提出了一个确定性的流水线——Extract-Gate-Rank ,通过读取 Linux 内核源代码来构建一个关系型数据库,以实现 ioctl 表面的物化。该过程基于一个覆盖 878 个模块、涉及 169 个子树的 allmodconfig 构建版本 (x86_64) 进行。
提取 (Extract):
利用基于 libclang 的内核源码知识图谱来识别 ioctl 调度器(绑定到 unlocked_ioctl、compat_ioctl 或 proc_ops.proc_ioctl 的函数)。
遍历调用闭包以定位至每个命令的处理函数体。
解码命令码: 解析器通过 UAPI 头文件展开 _IOC 宏,将 32 位命令码解码为四个字段:方向(direction)、大小(size)、魔数字节(magic byte)和序号(ordinal)。
识别汇点(Sinks)与门禁(Gates): 记录受控输入汇点(例如 copy_from_user)在固定调用跳数窗口内的位置,以及权限门禁(能力检查、LSM 钩子、f_mode 检查)。
净化启发式(Sanitization Heuristic): 如果在同一函数的源码顺序中不存在先前的硬性边界检查,则将该汇点标记为“未净化”。这是一种结构化代理,而非控制流证明。
过滤 (Gate):
应用威胁模型可达性过滤器 作为可查询列。
如果一个模块的 ioctl 路径缺乏硬性的 init-namespace 能力门禁(例如 CAP_SYS_ADMIN),则将其标记为 capability_ungated。
这作为非特权可达性的必要条件上界,而非对实际节点开放性的分类。它根据内核文档排除了 staging 驱动程序和 debugfs 路径。
排序 (Rank):
生成存储库之上的关系视图,优先考虑具有未净化汇点的 capability_ungated 调度器。
包括一个跨模块视图,用于对不同驱动程序中共享的命令码(类型、序号、访问权限)进行分组。
包含一个可选的 LLM 富化层用于分拣,但该层被保持在非关键路径上,并归入保留层级。
关键结果 该普查涵盖了 x86_64 allmodconfig 构建(占内建源码文件的 84%),并包含一个用于验证的 arm64 二次构建。
规模: 分析找回了 586 个 ioctl 调度入口点,分布在 337 个模块中,解码了 1,289 个唯一的 _IOC 命令码。
汇点与门禁: 识别出 3,583 个受控输入汇点和 1,298 个权限门禁。
可达性: 威胁模型过滤器排除了 50 个位于硬性能力门禁后的模块,将 281 个模块作为非特权可达性的上限。
架构覆盖率: 第二个 arm64 构建仅增加了一个唯一的模块(Apple adp_drv)且没有增加新的命令码,表明 x86_64 覆盖了 99.7% 的 ioctl 相关模块。
命令共享: 共享命令模式(例如 watchdog WDIOC_* 命令)在不同驱动程序中重复出现,这表明共享模式中的漏洞可能会同时影响许多模块。
能力集中度: 权限门禁主要由 CAP_SYS_ADMIN 主导(512 次出现),该能力在内核威胁模型中被明确视为“模型外”,从而进一步缩小了在研范围内的攻击面。
回测验证 作者针对 22 个近期内建 ioctl CVE 对普查进行了验证:
覆盖范围: 所有 22 个 CVE 均落在覆盖的子树内,消除了覆盖缺口作为误差来源的可能性。
恢复情况: 调度器恢复阶段找到了 7 个 CVE 的漏洞处理函数。
遗漏原因: 15 个遗漏 完全归因于注册模型的限制:
8 个案例涉及使用 ops-table 派发的 DRM/V4L2 核心(drm_ioctl_desc、v4l2_ioctl_ops),其中核心会在将参数传递给各命令处理函数之前先进行拷贝。
3 个案例涉及 tty 行规程(line disciplines)。
4 个案例涉及仅作为调度器下方被调用的函数。
过滤器准确性: 过滤器正确地准入了所有 7 个发现的 CVE。有两个关于节点 DAC(设备访问控制)限制的“错误准入”(例如 pci_endpoint_test),该方法正确预测了这一局限性,因为它不分析设备节点权限,仅分析能力门禁。
意义与主张 本文将 Linux IOCTL 普查定位为一种测量与数据集 的贡献,而非漏洞查找工具。其主要意义在于:
持久性与可查询性: 它将 ioctl 表面从瞬时的漏洞列表转变为持久的、可查询的关系型存储。这使得审计人员可以提出结构化问题(例如:“哪些模块共享此命令码?”),而漏洞列表无法回答此类问题。
威胁模型集成: 它将内核文档中的威胁模型直接编码进数据模式,将基于文本的安全性边界转化为可查询的过滤器。
互补性: 它通过枚举整个静态命令空间(包括可能缺乏 harness 或描述的命令),与动态模糊测试形成互补,从而引导动态工具转向未探索区域。
跨 OS 模式: 该数据集与配套的 Windows IOCTL 普查共享模式,从而实现跨平台查询。
局限性 作者明确说明了以下界限:
可达性: “用户可达”计数是基于能力门禁的上界,而非对节点开放性(DAC)的证明。
净化: “未净化”计数是基于源码顺序的启发式代理,而非形式化的安全性证明。
覆盖范围: 受限于 allmodconfig 构建所编译的内容;其他架构及无法共同启用的驱动程序被排除在外。
注册模型: 当前模型会遗漏通过 ops-tables(DRM、V4L2)、tty 行规程以及调度器下方辅助函数注册的处理函数。
数据集分为两个层级发布:一个公开的结构层 (模块、调度器、代码、门禁),采用开放许可;以及一个保留的目标层 (特定的汇点位置、富化结论以及排序后的非特权表面),以防止双重用途的利用,同时支持授权研究。
每周获取最佳 computer science 论文。
受到斯坦福、剑桥和法国科学院研究人员的信赖。
请查收邮箱确认订阅。
出了点问题,再试一次?
无垃圾邮件,随时退订。