使用LKM中的syscall表
作者:互联网
我正在从Linux(3.x)的syscall表中重写SYS_READ,但是在卸载模块本身时遇到了一些麻烦.
我首先加载我的模块,该模块找到syscall表,然后启用RW,使用我自己的SYS_READ函数覆盖SYS_READ(实际上,除了调用原始SYS_READ以外,它不执行其他任何操作),然后等待片刻,然后卸载模块.在模块的unload方法上,我将原始SYS_READ函数还原回syscall表中,并将syscall表重新设置为RO.
原始的SYS_READ函数已正确还原,但是在卸载模块时得到此信息:http://pastebin.com/JyYpqYgL
我想念什么?恢复真正的SYS_READ之后,我还应该做更多的事情吗?
编辑:GitHub链接到项目:https://github.com/alexandernst/procmon
编辑:
这是我获取系统调用表地址的方式:
void **sys_call_table;
struct idt_descriptor{
unsigned short offset_low;
unsigned short selector;
unsigned char zero;
unsigned char type_flags;
unsigned short offset_high;
} __attribute__ ((packed));
struct idtr{
unsigned short limit;
void *base;
} __attribute__ ((packed));
void *get_sys_call_table(void){
struct idtr idtr;
struct idt_descriptor idtd;
void *system_call;
unsigned char *ptr;
int i;
asm volatile("sidt %0" : "=m" (idtr));
memcpy(&idtd, idtr.base + 0x80 * sizeof(idtd), sizeof(idtd));
system_call = (void*)((idtd.offset_high<<16) | idtd.offset_low);
for(ptr=system_call, i=0; i<500; i++){
if(ptr[0] == 0xff && ptr[1] == 0x14 && ptr[2] == 0x85)
return *((void**)(ptr+3));
ptr++;
}
return NULL;
}
sys_call_table = get_sys_call_table();
这就是我设置RW / RO的方式:
unsigned long set_rw_cr0(void){
unsigned long cr0 = 0;
unsigned long ret;
asm volatile("movq %%cr0, %%rax" : "=a"(cr0));
ret = cr0;
cr0 &= 0xfffffffffffeffff;
asm volatile("movq %%rax, %%cr0" : : "a"(cr0));
return ret;
}
void set_ro_cr0(unsigned long val){
asm volatile("movq %%rax, %%cr0" : : "a"(val));
}
最后,这是我定义系统调用并更改系统调用表的方式:
asmlinkage ssize_t (*real_sys_read)(unsigned int fd, char __user *buf, size_t count);
asmlinkage ssize_t hooked_sys_read(unsigned int fd, char __user *buf, size_t count);
//set my syscall
real_sys_read = (void *)sys_call_table[__NR_read];
sys_call_table[__NR_read] = (void *)hooked_sys_read;
//restore real syscall
sys_call_table[__NR_read] = (void *)real_sys_read;
解决方法:
如果您希望卸载拦截系统调用的模块,请注意某些情况仍在系统调用处理程序中并且您的代码(模块的文本段)离开内存时的情况.这导致页面错误,因为当进程从某个内核函数(休眠)返回到您的代码时,该代码不再存在.
因此,正确的模块卸载方案必须检查挂钩系统调用中可能休眠的进程.仅当syscall挂钩中没有任何进程处于休眠状态时,才可以卸载.
UPD
请查看证明我的理论的补丁.它添加了在hooked_sys_read调用时递增和递减的原子计数器.因此,正如我想的那样,模块卸载后,仍在read_sys_read中等待一个进程.该补丁显示了printk(read_counter)并为我打印了1,这意味着某人不会减少read_counter.
标签:module,linux-kernel,c-3,linux 来源: https://codeday.me/bug/20191122/2063415.html