实践背景是开发云原生背景下的指纹识别插件,主要针对的是镜像、容器等云时代的软件资产。
信息安全语境下的 指纹识别 指的是定位软件的特征,如名称、版本号、开源许可证等,就像指纹是人的独特生物凭证,这些特征是软件的独特电子凭证。除了识别软件外,指纹识别还用于上报资产,即辅助探针发现镜像中的软件资产,包括组件、中间件、系统工具、系统库、CMS(Content Management System)等。
Trivy 是一个优秀的用于扫描镜像漏洞的开源工具,但商业场景下需要定制化开发,因此自研指纹识别工具。
根据知乎文章的介绍,Trivy 有以下特点:
因此自研产品应当对标 Trivy 且有一定改进,但在首次 Benchmark 测试时,针对 4.9G 大小的镜像,自研产品扫描用时 53 秒,且占用了一个 CPU 核。这个时间和硬件开销和 Trivy 相比是不可接受的,因此分析 CPU 用时信息。具体如何分析,见之前的博客 单元测试、基准测试和性能分析 。
分析 cpu.prof
后发现系统调用占了 38 秒,往上查找,发现 IsExist()
是主要的时间消耗对象,其底层实现是 Stat()
系统调用 。IsExist()
用于判断文件是否存在,但在遍历镜像的文件系统时,各个检测器都要对所有的文件进行检测(Detect
函数),而 Detect
函数中都有一个 IsExist()
判断,这将造成海量的系统调用,使检测速度大幅下降。
解决策略:
IsExist()
函数逻辑根本没必要,因为在遍历文件系统时不可能遍历到不存在的文件。因此修改代码逻辑后,系统调用大大减少,整体扫描时间下降至 14 秒。
所谓的重开销指的是消耗 CPU 资源,CPU 资源较为宝贵,因此需要合理分配。此外,从用户态陷入内核态时,还有上下文切换和现场保护,这部分也需要消耗较多资源。要理解为什么系统调用是重开销,就需要知道系统调用时发生了什么,进而分析哪些部分是开销大头。
系统调用(System Call,syscall)是用户态进程在请求系统资源时向操作系统内核发起的请求,如文件 I/O 操作、进程间通信等。这种将用户态与内核态隔离的方式,便于集中管理计算机资源,也使用户态的程序开发不需过多关注与硬件的交互。
根据中断触发来源的不同,可以将中断(Interrupt)分为 软件中断 和 硬件中断。
一般而言,系统调用是通过软件中断实现的,即 CPU 在执行特定指令时触发的。