作者 | beyondma 责编 | 张文 来源 | CSDN 博客 头图 | CSDN 下载自视觉中国 最近笔者遇到这样一个相对比较疑难的事件,某个在 Linux 下运行的杀毒软件启动后,在某些情况下 CPU 占用率会持续升高,而且在交易量较高的情况下极易复现。而奇怪的是,我们之前已经对于杀毒软件的 CPU 使用率进行了上限限定。出现这样异常事件表明:杀毒软件并没有执行之前设定的资源占用控制策略,CPU 使用率始终持续异常偏高。 分析下来这个事件还是很有借鉴意义的。 由于此事件涉及一些敏感信息,具体不便公开的细节就不透露了,仅把可以公开的情况梳理一下,供各位读者参考。 首先我们先明确一下钩子(hook)函数的概念,简单来讲这就是一类改变其它函数行为的函数。举个简单的例子,我每次进入会议室的时候都是直接推开门然后进入的,但是现在我在进入门之前要先向向会议室主持人申请,得到许可才能进入,那么向主持人申请的动作就被 attatch 到了进入会议室这个动作上了,整个过程就可以简单的理解为 hook。 我们知道在 Linux 下想改变系统的行为,需要代码运行的内核态。比如 kprobe、fsnotify 等机制,提供了 root 用户 hook 到内核代码的权限,并最终将自己的代码段 attach 到内核调用中。 CPU 使用率过高的原因分析 经确认这款杀毒软件的 CPU 占用率控制模型如下图,其守护模块会定时判断 agent 资源使用情况,如果超标则将释放扫描模块使用的 CPU 与内存资源。 但是具体分析下来,这样的机制在 IO 频繁的系统上存在缺陷,具体原因扫描模块在内核态下执行时下无法释放 CPU 资源。 分析过程如下: 经确认杀毒软件 agent 在行为监测时,在进程将文件加载到内存前,会使用 hook 技术对于 open 等系统调用进行 attach,确定加载的文件不含恶意代码后,才允许进程加载该文件。因此在 Linux 内核找到系统调用的 attatch 机制的相关代码进行分析。 1. 系统调用中 sys_open 函数,使用 fsnotify 机制对于 attach 注入到 sys_open 函数的进程进行回调通知。(具体代码位置在 kernel/open.c) 2. attach 到 sys_open 的代码执行过程始终是处于内核态中的,同时 Linux 的 fsnotify 机制也会加内核锁,在内核锁解锁前该进程无法释放 CPU,不能被打断。(具体代码位置在 kernel/fsnotify.c) 杀毒软件扫描模块 attach 内核函数的机制与 fsnotify 类似,因此其扫描模块在进行行为检测时会在内核态执行且不能被打断,而在系统中原本就有大量 IO 操作的情况下,守护模块将失效。 在 POC 测试时,该杀毒软件在文件扫描时其 CPU 占用率始终不高,这其中的原因是由于在扫描文件时该杀毒软件全部运行于用户态下,不存在内核态运行的情况,因此守护模块可正常调节 CPU 使用情况。 解决方案浅析 先说一下实测结论:在加入 attach 延时操作后,IO 吞吐量巨幅下降。经访照该杀毒软件的机制进行实测模拟,在内核 sys_open 函数 attach 加入延时操作,观察对于系统 IO 的影响。 在加入将内核 sys_open 延时一倍的操作后,我在华为的在鲲鹏 4C/8G 的平台实测上,每秒钟文件打开、关闭文件操作的次数,由每秒 867次 的峰值下降到了 72 次,出现了 90%以上的下降。这可能与内核锁的雪崩效应有关。 经确认,在之前的版本之所以没有出现问题,是由于当守护进程在确认 CPU 调节失效后会对自身 agent 进行整体自毁操作(modelu_exit),因此不会触发类似于 CPU 占用率持续升高的案例。 那么针对这样的机制具体的解决方案如下:
声明:本文为作者独立观点,不代表 CSDN 立场。 程序员如何避免陷入“内卷”、选择什么技术最有前景,中国开发者现状与技术趋势究竟是什么样?快来参与「2020 中国开发者大调查」,更有丰富奖品送不停! |