使用模块添加系统调用失败

内核编译和嵌入式产品的设计与开发
回复
zk012
帖子: 1
注册时间: 2010-11-10 10:03

使用模块添加系统调用失败

#1

帖子 zk012 » 2010-11-10 10:14

我不想编译内核来添加系统调用,所以采用模块的形式。我模块编译,安装,卸载都可以,但是就是在使用调用自定义系统调用程序的时候返回-1,表示调用失败,是什么原因呢?下面是我的模块:

#include<linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/unistd.h>
#include <linux/time.h>
#include <asm/uaccess.h>
#include<linux/fs.h>
#include <linux/sched.h>
#define __NR_mycall 338

MODULE_LICENSE("GPL");

static int (*anything_saved)(void);

asmlinkage int sys_mycall()
{
printk("hello world\n");
return 100;
}

// 中断描述符表寄存器结构
struct {
unsigned short limit;
unsigned int base;
} __attribute__((packed)) idtr;


// 中断描述符表结构
struct {
unsigned short off1;
unsigned short sel;
unsigned char none, flags;
unsigned short off2;
} __attribute__((packed)) idt;

// 查找sys_call_table的地址
void change_sys_call_table(void)
{
unsigned int sys_call_off;
unsigned int sys_call_table;
char* p;
int i;

// 通过sidt指令获取中断描述符表寄存器的地址,这里面包含有idt表的首地址
asm("sidt %0":"=m"(idtr));
printk(KERN_ALERT "in addr of idtr: %x\n", &idtr);

// 通过idtr里面的idt的首地址+偏移获取0x80中断处理程序的地址,由于idt中的每个门是64位,所以要乘以8,系统调用是0x80项,所以偏移为8*0x80。
memcpy(&idt, idtr.base+8*0x80, sizeof(idt));
//通过这项idt找到system_call的函数地址
sys_call_off=((idt.off2<<16)|idt.off1);
printk(KERN_ALERT "in addr of idt 0x80: %x\n", sys_call_off);

// 从0x80中断服务例程中搜索sys_call_table的地址,即通过找到第一个call指令的机器码8514ff来获取sys_call_table
p=sys_call_off;
for (i=0; i<100; i++)
{
if (p =='\xff' && p[i+1]=='\x14' && p[i+2]=='\x85')
{

sys_call_table=*(unsigned int*)(p+i+3);
unsigned int* sys_call_table_address = &sys_call_table;
printk(KERN_ALERT "in addr of sys_call_table: %x\n", sys_call_table);

//备份系统调用表中修改的那一项
anything_saved = (int(*)(void))(sys_call_table_address[__NR_mycall]);
//将这一项替换成自己的函数
sys_call_table_address[__NR_mycall] = (unsigned long)sys_mycall;

return ;
}
}
}

void undo_sys_call_table(void)
{
unsigned int sys_call_off;
unsigned int sys_call_table;
char* p;
int i;

// 获取中断描述符表寄存器的地址
asm("sidt %0":"=m"(idtr));
printk("out addr of idtr: %x\n", &idtr);

// 获取0x80中断处理程序的地址
memcpy(&idt, idtr.base+8*0x80, sizeof(idt));
sys_call_off=((idt.off2<<16)|idt.off1);
printk(KERN_ALERT "out addr of idt 0x80: %x\n", sys_call_off);

// 从0x80中断服务例程中搜索sys_call_table的地址
p=sys_call_off;
for (i=0; i<100; i++)
{
if (p =='\xff' && p[i+1]=='\x14' && p[i+2]=='\x85')
{
sys_call_table=*(unsigned int*)(p+i+3);
unsigned int* sys_call_table_address = &sys_call_table;
printk(KERN_ALERT "out addr of sys_call_table: %x\n", sys_call_table);
//将系统调用表中这项还原回来
sys_call_table_address[__NR_mycall] = (unsigned long)anything_saved;

return ;
}
}
}

int __init init_addsyscall(void)
{
//模块被insmod后就调用这个函数修改sys_call_table
change_sys_call_table();
return 0;
}

void __exit exit_addsyscall(void)
{
//模块被rmmod后就还原sys_call_table
undo_sys_call_table();
}

module_init(init_addsyscall);
module_exit(exit_addsyscall);

下面是我的调用程序:

#include <linux/time.h>
#include <linux/unistd.h>
#include <stdio.h>

#define __NR_mycall 338

int main()
{
printf("%d\n",syscall(__NR_mycall));

return 0;
}

被这个问题弄晕了 :em20 :em20 ,各位大大帮帮忙啊。
zhumeesfa
帖子: 1
注册时间: 2024-05-25 11:25
系统: windows

Re: 使用模块添加系统调用失败

#2

帖子 zhumeesfa » 2024-05-25 11:27

我也想问,你解决了吗
头像
astolia
论坛版主
帖子: 6570
注册时间: 2008-09-18 13:11

Re: 使用模块添加系统调用失败

#3

帖子 astolia » 2024-05-25 15:12

内核在处理syscall时会检查你使用的系统调用编号有没有超过编译内核时定义的系统调用总数
https://elixir.bootlin.com/linux/v6.9.1 ... mmon.c#L50
如果自定义编号比总数还大,那肯定通不过检查的

还有int 0x80是32位系统上的机制。现在普遍使用的64位系统上,一楼的代码并不适用。

最后,在现在的内核上,单纯处理系统调用并不需要sys_call_table了
https://elixir.bootlin.com/linux/v6.9.1 ... l_64.c#L14
回复