方案:利用linux内核钩子实现,钩子可以捕获到内核事件并做出额外处理。钩子的注册方式主要有两种,kproge和jprobe,jprobe是kprobe上层的封装,使用更加简单。submit_bio为块设备io请求的顶层函数,对其进行监听可实现对块设备io事件的监测。
过程:使用kprobe或者jprobe注册对应的内核符号(内核函数调用)进行监听,每当有对应的内核调用发生时,会优先执行钩子函数。
环境准备:下载uname -r对应的内核开发包(后续Makefile中编译选项-C指向其目录)
代码:
catch_bio.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/bio.h>
static void submit_bio_probe(int rw, struct bio * bio) {
if(bio && bio->bi_io_vec != NULL) {
char b[BDEVNAME_SIZE];
printk(KERN_INFO "device[%s] , type[%s] , offset[%10lld] , length[%d]" , bdevname(bio->bi_bdev, b), rw & WRITE ? "write" : "read" , bio->bi_sector, bio_sectors(bio));
}
jprobe_return();
}
static struct jprobe catch_bio_jprobe = {
.entry = (kprobe_opcode_t *) submit_bio_probe,
.kp = {
.addr = NULL,
.symbol_name = "submit_bio",
},
};
static int __init mod_init(void) {
int iRet = 0;
iRet = register_jprobe(&catch_bio_jprobe);
if(iRet < 0) {
printk(KERN_ERR "Module[catch_bio] init failed! Func register_jprobe failed, ret[%d]", iRet);
return iRet;
}
printk(KERN_INFO "Module[catch_bio] init successful.");
return iRet;
}
static void __exit mod_exit(void) {
unregister_jprobe(&catch_bio_jprobe);
printk(KERN_INFO "Module[catch_bio] exit successful.");
}
module_init(mod_init);
module_exit(mod_exit);
MODULE_LICENSE("GPL");
Makefile
KERNEL_DIR = /usr/src/kernels/`uname -r`
obj-m += catch_bio.o
all:
make -C $(KERNEL_DIR) M=`pwd` modules
clean:
make -C $(KERNEL_DIR) M=`pwd` modules clean
rm -rf *o *.mod.c *.order *.symvers
装载驱动:insmod catch_bio.ko
卸载驱动:rmmod catch_bio.ko
驱动监控结果输出:view /var/log/messages (结果如下图)
补充(其他常用的内核勾子点):
1. 系统调用勾子
sys_open
sys_read
sys_write
sys_execve
sys_clone
sys_fork
sys_exit
2. 网络勾子
nf_register_hook
/nf_unregister_hook
(Netfilter 勾子)dev_add_pack
/dev_remove_pack
(网络包接收勾子)inet_register_protosw
/inet_unregister_protosw
(协议勾子)
3. 文件系统操作
vfs_read
vfs_write
vfs_open
vfs_close
4. 进程管理
do_fork
do_exit
schedule
(调度函数)
5. 内存管理
__kmalloc
kfree
vmalloc
vfree
6. 驱动操作
register_chrdev
unregister_chrdev
register_blkdev
unregister_blkdev
7. 安全勾子(Linux Security Modules)
security_inode_create
security_file_open
security_task_create
security_socket_create
8. 其他重要勾子
register_filesystem
/unregister_filesystem
alloc_inode
/destroy_inode
module_load
/module_unload
(模块加载和卸载)