PrIntFuzz: Fuzzing Linux Drivers via Automated Virtual Device Simulation

ISSTA 2022,

Zheyu Ma , Bodong Zhao , Letu Ren , Zheming Li , Siqi Ma , Xiapu Luo , Chao Zhang .

PrIntFuzz

概述

Untitled

本文设计了一套高效的针对驱动程序的模糊测试框架PrIntFuzz,可以更加全面地测试驱动程序,包括之前的研究忽略的初始化程序和中断处理程序。PrIntFuzz利用过程间的域敏感,路径敏感和流敏感的静态分析从驱动程序中提取知识,然后利用这些知识生成虚拟设备,最后利用虚拟设备进行多维度的模糊测试。PrIntFuzz成功生成了311个虚拟PCI设备,472个虚拟I2C设备以及169个虚拟USB设备,并且在相应的驱动程序中发现了150个bug。

背景与挑战

由于Linux的重要性以及日益增长的复杂性,其安全性已经引起了学术界和工业界越来越多的关注。根据CVE的统计,在漏洞最多的前6个产品中,有5个都是Linux的发行版或者变种。在这些漏洞中,驱动程序漏洞的占比最大。由于驱动程序与操作系统内核共享地址空间以及权限,它们成为了攻击者的首要目标。攻击者通常通过从用户空间发出系统调用,或者由恶意设备发出的中断和恶意数据来利用驱动程序的漏洞,以获得内核的权限来发动进一步的攻击。现有的针对驱动程序的模糊测试方案存在以下挑战:

  1. 对虚拟设备的多样性支持不够,许多驱动程序无法测试。比如USBFuzz[1]仅能支持虚拟USB设备。
  2. 模拟出来的虚拟设备的功能有限,使得相应驱动程序的代码覆盖率较低。根据研究,驱动程序代码的主要组成部分有初始化、中断请求、电源管理、IOCTL以及错误处理等,现有的解决方案只能模拟少数功能,不能覆盖更多的驱动程序代码。
  3. 对驱动程序的攻击面探索不够深入。驱动程序可能接受来自不同来源的输入,包括用户空间的系统调用以及恶意设备发送的恶意输入。现有方案没有从多个攻击面探索对驱动程序的攻击。

PrIntFuzz

针对以上方案的问题,我们提出了PrIntFuzz,一个用于探索Linux设备驱动中初始化程序和中断处理程序的模糊测试系统,它利用静态分析提取的驱动信息来生成虚拟设备,然后对驱动程序进行多维度模糊测试。PrIntFuzz的工作流程分为三个阶段,如图所示。

Untitled

首先,在虚拟设备建模阶段,PrIntFuzz从两个方面对虚拟设备进行建模。PrIntFuzz首先通过过程间流敏感、路径敏感和域敏感的静态分析,提取必要的驱动程序信息,例如驱动所依赖的数据空间以及内存空间和配置空间,然后利用这些信息为驱动程序创建大量的虚拟设备,为模糊测试做准备。另一个是生成系统调用模板,包含各种系统调用的描述。Fuzzer将利用这些模板来生成系统调用序列,以便与设备驱动程序进行交互。 其次,在驱动准备阶段,PrIntFuzz需要在内核的配置中启用这些驱动程序。尽管allyesconfig和menuconfig提供了配置所有驱动程序或手动选择驱动程序的功能,但它们不能自动配置大量的特定驱动程序。然后,PrIntFuzz实现了一种错误注入方法,在驱动初始化代码中注入软件错误。错误注入的目的是测试驱动程序初始化代码的错误处理代码,这在正常执行中很少被测试。

第三,在QEMU的模糊测试阶段,PrIntFuzz首先创建了虚拟设备,然后模拟了一些设备的功能,最后从用户空间程序和硬件进行多维度的模糊测试,如图所示。

Untitled

实验

PrIntFuzz的有效性主要体现在以下几个方面:

PrIntFuzz模拟设备的能力

Untitled

VIA可以模拟22个设备,包括11个PCI设备,QEMU可以模拟223个设备,包括139个PCI设备,而PrIntFuzz基于QEMU支持另外281(=420-139=504-223)个PCI设备。VIA可以扩展到支持更多的虚拟设备,但需要大量的手工工作来编写配置模板。

PrIntFuzz发现bug的能力

Untitled

PrIntFuzz已经发现了112个其他fuzzers没有发现的Linux内核中的PCI驱动的unique bug,到目前为止,其中50个已经被patch。如表所示,PrIntFuzz在Linux PCI驱动中发现了许多不同类型的bug,包括空指针解引用、Use-After-Free、OOB和Double Free以及其他类型的bug。

PrIntFuzz探索代码的能力

Untitled

除了发现bug的能力之外,我们还评估了PrIntFuzz与Syzkaller相比在Linux内核5.18-rc1上的代码覆盖率的提升。在这个实验中,我们只对内核的drivers和sound目录进行了插装。同时,我们为每组实验添加了一个baseline,它使用Syzkaller 默认的系统调用模板进行模糊测试,而不需要添加额外的模板或虚拟设备,这样可以更好地看清PrIntFuzz的提升效果。

PrIntFuzz的可扩展性

Untitled

上表显示了PrIntFuzz模拟的USB和I2C设备的数量。总的来说,PrIntFuzz成功地模拟了346个USB设备中的169个和895个12C设备中的472个,这充分表明了PrIntFuzz的方法是有效的且可扩展的。

总结

由于支持设备的多样性不足,现有的驱动程序模糊测试方案忽略了很大一部分的驱动程序代码,即初始化代码和中断处理代码。PrIntFuzz通过自动模拟虚拟设备来解决这个问题,它支持设备初始化、主动发起硬件中断和处理硬件I/O数据拦截。基于对虚拟设备的支持,PrIntFuzz进行了多维度的模糊测试,结合多种方法来影响驱动程序的控制流和数据流,如系统调用交互、中断注入和数据注入等。PrIntFuzz能够显著地提升代码覆盖率以及发现更多的bug。

作者介绍:马哲宇,清华大学网络科学与网络空间研究院博士生,导师是张超老师。他的主要研究方向为模糊测试、内核安全以及虚拟化安全,联系方式:[email protected]