三、实验二
1.任务
用内核模块的方式为系统添加一个系统调用。
要求该系统调用能够完成以下功能:
(1) 该系统调用有1个整型参数,接收输入自己的学号;
(2) 若参数为奇数,则返回自己学号的最后5位。如你的学号为130120101 ,则返回20101;
(3) 若参数为偶数,则返回自己的学号的最后6位。如你的学号为130120102 ,则返回120102 。
2.过程
- 得到sys_call_table的地址
grep sys_call_table /boot/System.map-`uname -r`
cat /proc/kallsyms | grep sys_call_tables
- 查看预留的系统调用号。
cd /usr/src/linux-2.6.32.60/arch/x86/include/asm
sudo gedit unistd_32.h
文件中查看预留的系统调用号。
可以看出223就是一个预留的系统调用号。
- 改内核程序源代码:
.c
文件
cd ~
mkdir project2 && cd project2
gedit burgerModule.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#define sys_call_table_adress 0xc0583110
int orig_saved=0;
unsigned long* sys_call_table = 0;
int make_rw(unsigned long address);
int make_ro(unsigned long address);
asmlinkage long sys_mycall2(int num);
int make_rw(unsigned long address)
{
unsigned int level;
pte_t *pte = lookup_address(address, &level);//查找虚拟地址所在的页表地址
if (pte->pte & ~_PAGE_RW) //设置页表读写属性
pte->pte |= _PAGE_RW;
return 0;
}
int make_ro(unsigned long address)
{
unsigned int level;
pte_t *pte = lookup_address(address, &level);
pte->pte &= ~_PAGE_RW; //设置只读属性
return 0;
}
static int syscall_init_module(void)
{
sys_call_table = (unsigned long*)sys_call_table_adress;//获取系统调用服务首地址
printk(KERN_ALERT "sys_call_table: 0x%p\n", sys_call_table);//获取系统调用表的地址
orig_saved = (unsigned long *)(sys_call_table[223]); //保存原有的223号的系统调用表的地址
printk(KERN_ALERT "orig_saved : 0x%p\n", orig_saved );
make_rw((unsigned long)sys_call_table); //修改页的写属性
sys_call_table[223] = (unsigned long *)sys_mycall2; //将223号指向自己写的调用函数
make_ro((unsigned long)sys_call_table);
return 0;
}
asmlinkage long sys_mycall2(int num){
printk("your number is %d\n",num);
if(num%2==0)
return num%1000000;
else
return num%100000;
}
static void syscall_cleanup_module(void)
{
printk(KERN_ALERT "Module syscall unloaded.\n");
make_rw((unsigned long)sys_call_table);
sys_call_table[223] = (unsigned long *) orig_saved ;
make_ro((unsigned long)sys_call_table);
}
module_init(syscall_init_module);
module_exit(syscall_cleanup_module);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("mysyscall");
gedit Makefile
obj-m := burgerModule.o
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
make
sudo dmesg -c
sudo insmod burgerModule.ko
- 查看要关注的信息
- 查看
printk
的输出在缓冲区的信息:
dmesg
- 调用系统调用的信息
gedit helloworld.c
#include<stdio.h>
int main()
{
int t;
scanf("%d",&t);
printf("%d\n",syscall(223,t));
return 0;
}
gcc helloworld.c
./a.out
- 卸载信息
sudo rmmod burgerModule
sudo dmesg -c