导语:Linux Kernel reducer可以监控 Linux 内核构建过程中被访问的文件。

在Android中,Linux内核是安全性的关键,因为它负责对系统中的所有内容执行访问控制。如果攻击者可以在内核模式下获得任意代码执行,那么就可以绕过应用程序沙箱,直接访问硬件等。

多年来,Linux内核源代码已经在显着增长。它包含所有支持的功能的代码,包括在多个支持的体系结构中的各种硬件的驱动程序。在现代Linux内核源代码树相当繁杂。在本文中,我们的例子中使用的树有729兆字节。

dev:0:/android/source/kernel/msm$ du -hs . --exclude .git
729M

现在,你可能会想知道为什么大小很重要。为了更好的理解,让我们把自己放在鲍勃的实际工作中,他是一名职业的代码审计。很多公司都会聘请他阅读大量的源代码来发现和修复代码中的错误和或漏洞。鲍勃的成功是由于他设计并执行了一个最有效地使用他的时间的策略。

一些审计人员可能选择使用自动化工具,还有一些审核员可能会选择手动阅读代码。鲍勃喜欢更聪明地工作,所以他开发了一套正则表达式,他运行内核代码来识别潜在的问题。在筛选结果并分析周围的代码后,他发现了一个比较严重的驱动问题。他拉出项目的测试设备,并快速发现驱动程序未加载。不好!现在鲍勃对此感到非常好奇,于是他伸出援手,询问“Droid Army”中的哪些Android设备正在使用驱动程序。不幸的是,没有设备使用该驱动程序。在我看来,这代表了鲍勃的战略错误,导致他浪费了时间。有没有办法来避免这一命运呢?答案是“有”。

工具

Linux内核减速器,或简称为lk-reducer。这个工具有助于避免我们迄今为止讨论过的一些问题。它可以在构建Linux内核时监视文件系统访问。(绝对不是它的实用程序仅限于Linux内核,但它只是我们需要的地方。)这是可能的,因为提供Linux内核源代码是Linux GNU公共许可证(LGPL)下的法定要求。通过监视构建过程,我们可以确定源树中的哪些文件已被用于构建最终的内核映像。某些文件将不可避免地被使用,因此我们可以确定它们并不是必需的。因此,在源代码审核期间,它们可以被忽略。而这就可以在手动和自动源代码审查过程中节省不少时间。

示例

一旦下载并编译了该工具,请给它提供一个Linux内核源码树的路径:

dev:0:lk-reducer$ ./lk-reducer /android/source/kernel/msm
dev:0:msm$

现在,构建Linux内核来跟踪哪些文件被访问。记住不仅要配置和构造内核,还包括清理构造。否则,我们可能会错过在清理过程中使用的文件,最后使用我们可以构造但不必清理的树。 

dev:0:msm$ export ARCH=arm64 SUBARCH=arm64 CROSS_COMPILE=aarch64-linux-androidkernel-
dev:0:msm$ make marlin_defconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  SHIPPED scripts/kconfig/zconf.tab.c
  SHIPPED scripts/kconfig/zconf.lex.c
  SHIPPED scripts/kconfig/zconf.hash.c
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTLD  scripts/kconfig/conf
drivers/soc/qcom/Kconfig:381:warning: choice value used outside its choice group
drivers/soc/qcom/Kconfig:386:warning: choice value used outside its choice group
#
# configuration written to .config
#
dev:0:msm$ make
scripts/kconfig/conf --silentoldconfig Kconfig
drivers/soc/qcom/Kconfig:381:warning: choice value used outside its choice group
drivers/soc/qcom/Kconfig:386:warning: choice value used outside its choice group
  CHK     include/config/kernel.release
[... further build output omitted for brevity ...]
  DTC     arch/arm64/boot/dts/htc/msm8996-v3-htc_sailfish-xb.dtb
  GZIP    arch/arm64/boot/Image.gz
  CAT     arch/arm64/boot/Image.gz-dtb
dev:0:msm$ make mrproper
  CLEAN   .
  CLEAN   arch/arm64/kernel/vdso
  CLEAN   arch/arm64/kernel
  CLEAN   crypto/asymmetric_keys
  CLEAN   kernel/time
  CLEAN   kernel
  CLEAN   lib
  CLEAN   net/wireless
  CLEAN   security/selinux
  CLEAN   usr
  CLEAN   arch/arm64/boot/dts/htc
  CLEAN   arch/arm64/boot
  CLEAN   .tmp_versions
  CLEAN   scripts/basic
  CLEAN   scripts/dtc
  CLEAN   scripts/kconfig
  CLEAN   scripts/mod
  CLEAN   scripts/selinux/genheaders
  CLEAN   scripts/selinux/mdp
  CLEAN   scripts
  CLEAN   include/config include/generated arch/arm64/include/generated
  CLEAN   .config .version include/generated/uapi/linux/version.h Module.symvers
dev:0:msm$

完成构造和清理流程后,只需退出子shell即可生成数据文件: 

dev:0:msm$ exit
exit
processing remaining events...
inotify event collection phase is over, dumping results to "lk-reducer.out"...
cleanup complete

从这里开始,你就可以分析数据文件,并选择是否从当前源代码树中删除文件或将其复制到另一个地方。我个人比较倾向于将文件复制到另一个目录并从那里进行审核。

注意:如果你正在使用Git的树,那么你可能需要过滤掉.git子目录,就像我在这里完成的那样。你可以随时查看原始存储库中的历史记录。 

dev:0:msm$ grep ^A lk-reducer.out | cut -c 3- | grep -v './.git/' > lk-reducer-keep.out
dev:0:msm$ mkdir ../msm-marlin-reduced
dev:0:msm$ tar cf - -T lk-reducer-keep.out | tar xf - -C ../msm-marlin-reduced/
dev:0:msm$ du -hs ../msm-marlin-reduced/
132M    ../msm-marlin-reduced/

如你所见,我们将源代码从729兆字节缩小到只有132兆字节。更重要的是,我们知道最后的内核映像没有内置的代码。

当然,这不是在审计Linux内核时面临的唯一问题。即使我们已经删除了在构建时未被访问的代码,由于探测,系统配置或其他可能无法控制的状态,一些剩余的代码可能无法使用。此外,文件中的代码可能仍然会被预处理器抛出,或者在编译期间被优化。此外,此工具无法帮助你了解威胁模型或确定可能对审核感兴趣的攻击面。 

结论

这篇文章定义了Linux内核研究员们面临的一个问题,并提出了一个旨在帮助解决问题的工具。我们很高兴地发布这个工具来协助社区进行Linux内核的源代码审核。我们希望该工具能为你节省时间,使你更有效率。你可以在Github上找到该工具。

源链接

Hacking more

...