为linux内核增加系统新调用实现获取进程数的方法

为linux内核增加系统新调用实现获取进程数的方法

Posted by lwk on June 3, 2020

阅读本文之前还是建议读者先了解下系统调用,可参考之前的文章说一说linux的系统调用

大部分人都是通过ps获取机器的进程数,但ps不但消耗大量的系统调用,而且在异常情况下可能会卡死,因为ps命令主要是通过读取/proc目录下的文件获取进程相关信息的。

因此本文通过为linux内核增加系统调用,实现一次系统调用获取系统进程数。

本文使用内核版本:5.5.0

首先在arch/x86/entry/syscalls/syscall_64.tbl增加系统调用表,当前系统调用号已经到了547,因此我们使用的系统调用号从548开始。

image 在include/linux/syscalls.h增加系统调用函数声明

image

在kernel/sys.c增加函数定义

image

内核每个进程的结构(PCB)是task_struct,用链表进行管理。因此只需要遍历链表获取链表长度就是进程数。

make menuconfig (load->save->exit)

make –j8 (8是机器的cpu核数,具体根据机器配置设置)

make modules

make modules_install

make install

查看/lib/modules目录下是否生成新内核 image 设置启动引导,启动默认使用5.5内核启动。

image 重启系统。。。。。。

查看系统内核版本,已经是最新内核了

image

OK,接下来编译测试程序t.c

测试程序如下:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char* argv[])

{
    intproc_count = syscall(548);
   printf("current system has process counts: %ld\n",proc_count);
   return 0;

}

注:由于没有修改GLIBC,所以测试程序直接通过系统调用号调用。

编译:gcc –o t t.c

测试结果: image

和ps的耗时对比:

image

可能有些人看到上面时间相差不大,主要是由于我自己的测试机没有业务进程,当有成千上万个进程的时候,耗时还是比较明显的。

总结:本文主要通过增加系统调用方式获取当前系统的进程数,之前都是通过ps获取进程数信息,但ps消耗系统性能,而且当系统异常时可能出现卡住问题,不靠谱。但通过增加系统调用,直接获取PCB链表的长度,大大减少了系统调用,提高了效率,减少了性能损耗。

其实之前一直想这个问题怎么去实现,但一直没有动手操作过,花了2个小时(编译内核比较久,而且中间又出现过失败)才搞定。

其实除了这种方法,还有其他方式(不编译内核)可以实现,那就是增加内核模块(KO),通过增加KO也是可以实现的。

另外,在内核安全方面,通过增加特定系统调用捕获恶意访问或调用,实现类似audit审计系统及时发现异常;另外也可以通过增加系统调用和KO实现截获系统调用(例如挖矿程序),及时发现是否有人利用线上机器进行挖矿。(PS:请将技术用在正道上^_^)