博文

目前显示的是标签为“syscall”的博文

模块添加syscall

在《添加一个syscall》一文中需要修改内核源码和重新编译安装内核才能添加自己的系统调用,这太浪费时间了,调试也很不方便,这次准备实现一个内核模块来添加syscall,这样就不再需要漫长的等待了。 一旦内核编译完成后,其系统调用表大小已确定下来,如果在其后追加,很容易造成内存溢出问题,故而这里只是替换《添加一个syscall》里的314号新增系统调用,既然要替换,那么先要获得系统调用表的起始位置,可由如下方法获得: 1.编译后的Linux源码目录下的System.map文件; 2./proc/kallsyms; 3./boot/System.map-3.13.6 (具体对应自己的版本,我的是3.13.6); 在上面任一文件搜索sys_call_table,即可得到系统调用表的入口位置:  ffffffff818013c0 R sys_call_table 其中, ffffffff818013c0是64位系统对应的系统调用表入口(我机器上的),R表示该地址是只读的,我们肯定是没有写的权限了,但是Intel的相关手册里有说到CR0(控制寄存器0)的bit 16(第17位)是写保护标志,当该位置位(为1)时只读,清零(为0)时则可读写,那我们玩一个花样就是在修改314号系统调用对应的处理函数时,让bit16为0,改好后恢复原来值,卸载模块时修改314号系统调用为原来对应的函数,这里面会用到内核源码里的宏X86_CR0_WP和read_cr0()以及write_cr0()两函数,均在源码里有注明,模块源码如下: #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/sched.h> #include <uapi/asm/processor-flags.h> //X86_CR0_WP #include <asm/special_insns.h> //read_cr0(),writ...

添加一个syscall

我们之前学习的各种内核态与用户态数据交换时都需要系统调用,只是我们没感受到,而这次我们向内核添加一个自己的syscall,来感受下这一功能的特殊魅力。 下面说明在Kernel源码里如何添加一个syscall: 1.在include/linux/syscalls.h文件里最后一行的#endif前添加自己的系统调用函数声明,内容如下: asmlinkage long sys_slam(void); 2.在kernel/sys.c文件中,我们在SYSCALL_DEFINE0(getegid) 定义后面添加上面函数的定义,内容如下: SYSCALL_DEFINE0(slam) { printk("Hello slam call!\n"); return THREAD_SIZE; } 这里的 SYSCALL_DEFINE0宏表示我们的系统调用是无参的,该宏在上面syscalls.h头文件中定义。 3.添加系统调用向量,在arch/x86/syscalls/syscall_64.tbl文件中添加系统调用号和系统调用服务程序入口(如果是32位系统,则修改syscall_32.tbl文件),在313号系统调用后面添加如下内容: 314 common slam sys_slam 4.配置完内核后,我们重新编译安装Kernel,在源码根目录下使用make和sudo make install命令; 5.重启机器后需要写一个用户态的应用程序来测试添加的系统调用是不是成功,我们创建一个文件slam_syscall.c,文件内容如下: #include <linux/unistd.h> #include <sys/syscall.h> #include <stdio.h> int main(void) { long stack_size = syscall(314); printf("The kernel stack size is %ld\n", stack_size); return 0; } 相应的Makefile文件内容如下: all: gcc -o slam_syscall slam...