当前课程知识点:Linux 内核分析与应用 > 第6章 系统调用 > 6.3 动手实践-添加系统调用(系统调用日志收集系统) > Video
大家好 今天我们基于Linux5.0内核添加一个系统调用
但是单纯添加一个系统调用会显得有些单调
所以我们把系统调用 工作队列
修改内核 内核编译
还有内核模块的编写 插入等等结合起来
我们要添加的是一个系统调用日志收集系统
系统调用是用户程序与系统打交道的入口
系统调用的安全直接关系到系统的安全
假设一个用户他恶意的不断调用fork
将会导致系统负载增加
所以如果能收集到是谁调用了一些有危险的系统调用
以及系统调用的时间和其他信息
将有助于系统管理员进行事后的追踪
从而提高系统的安全性
下面我们看到的这张图就是本次要添加的系统调用日志收集系统示意图
我们可以看到当用户进程进行系统调用的时候
当执行到do_syscall_64
我们判断是否是我们需要记录的系统调用
如果是 则拦截需要记录的系统调用
通过my_audit这一函数
相关信息写入到内核中的buffer里
同时我们编写用户测试程序
在用户测试程序中通过我们本次添加的
335号系统调用执行my_sysaudit这一函数
该函数把内核buffer里的信息拿到我们的用户buffer当中
其中my_audit和my_sysaudit
这两个函数是钩子函数
并且在我们的my_audit内核模块当中进行具体的实现
接下来我们来看具体的实现步骤
首先我们可以看到目前系统是Intel x86指令体系架构下
4.15版本的内核
我们将在5.0版本内核上添加系统调用
首先进入到相关目录下
下载5.0版本内核
可以使用wget命令进行下载
可以看到这里已经下载好了
之后我们解压下载好的压缩包
解压的步骤我们省略 接着进入我们解压好的5.0内核源码
添加系统调用第一步 打开系统调用表表项文件 增加系统调用表表项
我们进入到相关目录下
在这里我们添加335号系统调用
注意要按照上面的格式进行添加
接着我们保存
第二步 添加系统调用函数
同样也要进入相关目录下进行添加
可以看到这里提前写好并且复制过来了
这里使用内核所给的SYSCALL_DEFINE宏
定义了系统调用在内核的入口
同时声明了两个钩子函数在内核模块中等待实现
保存
第三步 修改Makefile文件
把myaudit.c添加到内核编译中去
也就是这里
保存
第四步 增加函数声明
同样我们要进入相关目录下
要注意的是
一定要在最后endif之前添加函数声明 也就是这里
保存 第五步 拦截相关系统调用
我们首先找到do_syscall_64这个函数
在这个地方加入对系统调用号nr的判断
如果是我们需要拦截的系统调用号 我们就将它拦截下来
我们可以看到要记录的系统调用号有
2号open 3号close 39号get_pid
56号clone 57号fork 59号exit
如果是我们需要记录的系统调用函数
我们就调用之前的钩子函数my_audit
如果我们还没有在内核模块中实现my_audit
就打印日志my_audit is not exist 然后保存退出
接下来我们编译内核
可以看到当前的内核版本是4.15
那么我们把当前内核的.config文件拷贝到当前目录下
之后我们执行make menuconfig
加载.config文件
保存并退出
顺序就是load ok save ok exit exit
接着我们执行make olddefconfig
之后我们编译内核
需要注意的是如果你使用的是ubuntu系统
直接make menuconfig有时候会报错
需要安装几个依赖的库
由于内核编译时间过长
我们把内核编译的过程省略掉
之后我们装内核
并且修改内核引导
然后重启系统
可以看到我们当前内核版本为5.0
下来我们要做的是添加实现钩子函数的内核模块
所以进入到相应目录下打开my_audit.c文件
这个内核模块之前写好了
可以看到我们首先定义了一个结构体
这个结构体就存放了我们要获取的一些系统调用的属性
接下来我们实现了两个函数
syscall_audit这一函数
实现了把拦截下的系统调用参数赋给我们定义的结构体
而sys_audit
则实现了把内核的buffer拿到用户的buffer中
这两个函数就挂在我们之前在内核中定义的两个钩子函数上
可以看到模块加载的时候会把它赋过去
模块卸载的时候就会把这个钩子函数重新置为空
之后我们看一下现在内核之中的日志
可以看到日志中打印了很多 my_audit is not exist
因为我们还没有插入内核模块 所以当然找不到这个函数
这个钩子函数当然就为空
之后我们编写Makefile文件
把my_audit.c编译成为内核模块
接着我们对my_audit.c进行编译
接着我们插入编译好的内核模块
插入之后我们再来看看日志
在日志的最后一行我们可以看到yes,it near full
这说明我们内核中的buffer已经快满了
这时候我们编写用户态测试程序
我们可以看到这里有相同的结构体
是用户态下的buffer里面存放的数据
这里我们通过调用335号系统调用
而335号系统调用对应之前我们所写的钩子函数
把内核态的buffer取到我们用户态的buffer中
接着打印出来就可以了
我们来看一下他的执行结果
执行我们的用户态测试程序
我们可以看到测试程序一运行就打印出了许多
拦截到的系统调用的相关日志
并且随着操作系统的执行
也在不断记录一些信息 并且在不断的打印
我们现在再来看这张图就很清晰了
用户进行我们需要记录的系统调用时
会被my_audit进行拦截
存在内核的buffer里
我们使用用户态测试程序
进行335号系统调用
把内核buffer里的信息拿出到用户态buffer里进行打印
这就是我们本次添加日志收集系统的全过程
谢谢大家
-1.1 Linux操作系统概述
-1.2 Linux内核结构以及内核模块编程
--Video
-1.3 Linux内核源码中的双链表结构
--Video
-1.4 源码分析-内核中的哈希表
--Video
-1.5 动手实践-Linux内核模块的插入和删除
--Video
-第1章 概述--章节测验
-2.1 内存管理之内存寻址
--Video
-2.2 段机制
--Video
-2.3分页机制
--Video
-2.4 动手实践-把虚拟地址转换成物理地址
--Video
-第2章 内存寻址--章节测验
-3.1 进程概述
--Video
-3.2 Linux进程创建
--Video
-3.3 Linux进程调度
--Video
-3.4 动手实践-打印进程描述符task_struct中的字段
--Video
-3.5工程实践-基于内核模块的负载监控
--Video
-第3章 进程管理--章节测验
-4.1 Linux内存管理机制
--Video
-4.2 进程用户空间管理机制
--Video
-4.3 物理内存分配与回收机制(上)
--Video
-4.4 物理内存分配与回收机制(下)
--Video
-4.5 动手实践-Linux内存映射基础(上)
--Video
-4.6 动手实践-Linux内存映射实现(中)
--Video
-4.7 动手实践-Linux内存映射测试(下)
--Video
-4.8 初学者对内存管理的常见疑惑
-第4章 内存管理--章节测验
-5.1 中断机制概述
--Video
-5.2 中断处理机制
--Video
-5.3 中断下半部处理机制
--Video
-5.4 时钟中断机制
--Video
-5.5 动手实践-中断上半部的代码分析及应用
--Video
-5.6 动手实践-中断下半部的代码分析及应用
--Video
-第5章 中断--章节测验
-6.1 Linux中的各种API
--Video
-6.2 系统调用机制
--Video
-6.3 动手实践-添加系统调用(系统调用日志收集系统)
--Video
-第6章 系统调用--章节测验
-7.1 内核同步概述
--Video
-7.2 内核同步机制
--Video
-7.3 动手实践-内核多任务并发实例(上)
--Video
-7.4 动手实践-内核多任务并发实例(下)
--Video
-第7章 内核同步--章节测验
-8.1 虚拟文件系统的引入
--Video
-8.2 虚拟文件系统的主要数据结构
--Video
-8.3 文件系统中的各种缓存
--Video
-8.4 页高速缓存机制以及读写
--Video
-8.5 动手实践-编写一个文件系统(上)
--Video
-8.6 动手实践-编写一个文件系统(中)
--Video
-8.7 动手实践-编写一个文件系统(下)
--Video
-第8章 文件系统--章节测验
-9.1 设备驱动概述
--Video
-9.2 I/O空间管理
--Video
-9.3 设备驱动模型
--Video
-9.4 字符设备驱动程序简介
--Video
-9.5 块设备驱动程序简介
--Video
-9.6 动手实践-编写字符设备驱动程序
--Video
-9.7工程实践-编写块设备驱动的基础(上)
--Video
-9.8 工程实践-块设备驱动程序分析(中)
--Video
-9.9 工程实践-块设备驱动程序实现(下)
--Video
-第9章 设备驱动--章节测验
-致谢与说明
--Video