| 论坛注册| 加入收藏 | 设为首页| RSS
Google
您当前的位置:首页 > Linux频道 > Linux开发区 > 软件开发

FC6增加系统调用

时间:2007-08-17 10:32:30  来源:Linux联盟收集整理  作者:八戒
系统:32位x86系统BBdLinux联盟
OS:FC6BBdLinux联盟
内核版本:2.6.18BBdLinux联盟
目的:新增一个系统调用,将当前进程的UID和EUID都设置成0(超级用户)BBdLinux联盟
步骤:BBdLinux联盟
1 内核源码树位置:SRC=/usr/src/redhat/BUILD/kernel2.6.18/linux-2.6.18.i386BBdLinux联盟
BBdLinux联盟
2 增加新系统调用号,修改头文件BBdLinux联盟
$SRC/include/arm-i386/unistd.hBBdLinux联盟
   。BBdLinux联盟
   。BBdLinux联盟
   。BBdLinux联盟
#define __NR_splice             313BBdLinux联盟
#define __NR_sync_file_range    314BBdLinux联盟
#define __NR_tee                315BBdLinux联盟
#define __NR_vmsplice           316BBdLinux联盟
#define __NR_move_pages         317BBdLinux联盟
#define __NR_mysyscall          318 /*新增加的一行,其中318是系统调用号,BBdLinux联盟
                                    根据系统不同自己定义与已经有的系统BBdLinux联盟
                                   调用号不相同即可*/BBdLinux联盟
3 修改系统调用表。修改文件BBdLinux联盟
$SRC/arch/i386/kernel/syscall-table.s(注意,以前版本的内核应该修改和前面文件同BBdLinux联盟
BBdLinux联盟
级目录下的entry.s)BBdLinux联盟
ENTRY(sys_call_table)BBdLinux联盟
        .long sys_restart_syscall       /* 0 - old "setup()" system call, usedBBdLinux联盟
BBdLinux联盟
for restarting */BBdLinux联盟
        .long sys_exitBBdLinux联盟
        .long sys_forkBBdLinux联盟
        .long sys_readBBdLinux联盟
        .long sys_writeBBdLinux联盟
        .long sys_open          /* 5 */BBdLinux联盟
        .long sys_closeBBdLinux联盟
        .long sys_waitpidBBdLinux联盟
        .long sys_creatBBdLinux联盟
        .long sys_linkBBdLinux联盟
        .long sys_unlink        /* 10 */BBdLinux联盟
        .BBdLinux联盟
        .BBdLinux联盟
        .BBdLinux联盟
        .long sys_mysyscall           /*新增加一行*/BBdLinux联盟
BBdLinux联盟
BBdLinux联盟
4 定义新系统调用的具体内容,一般可以直接在$SRC/kernel/sys.c中添加,BBdLinux联盟
当然也可以加入与其功能紧密联系的代码中去。这里我加在$SRC/kernel/sys.c中,BBdLinux联盟
在该文件末尾加入:BBdLinux联盟
asmlinkage int sys_mysyscall(void)BBdLinux联盟
{BBdLinux联盟
        current->uid = current->euid  = 0;BBdLinux联盟
        return 0;BBdLinux联盟
}BBdLinux联盟
BBdLinux联盟
5 通常我们在用户层使用系统调用都是通过C库支持来使用的,也就是说C库中对系统调用BBdLinux联盟
BBdLinux联盟
进行了一次封装BBdLinux联盟
,可以通过查看glibc的源码可以看到具体封装过程。由于glibc十分庞大,如果我们自己BBdLinux联盟
BBdLinux联盟
新定义对上面新增BBdLinux联盟
系统调用的C库函数的话,编译时间太长,所以我想直接利用LINUX提供的宏_syscallN来完BBdLinux联盟
BBdLinux联盟
成。BBdLinux联盟
其中N是系统调用的参数个数。举例说明该宏的用法:BBdLinux联盟
对于系统调用open()的定义本来是:BBdLinux联盟
long open(const char* filename,int flags,int mode)BBdLinux联盟
如果不靠c库支持使用该系统调用方法如下:BBdLinux联盟
#define __NR_open 5  /*5是open的系统调用号*/BBdLinux联盟
_syscall3(long,open,const char* filename,flags,mode)BBdLinux联盟
有了这些定义后下面对open可以直接调用了BBdLinux联盟
(一般书上都会讲到这种方法),但是在实际操作过程中,会发现在2.6.X中,已经取消了BBdLinux联盟
BBdLinux联盟
宏_syscallN的定义,所以BBdLinux联盟
你在编译的时候是通不过的。当然2.6取消了这些宏定义,我们可以自己在版本的代码中找BBdLinux联盟
BBdLinux联盟
出这些宏定义加上即BBdLinux联盟
在2.4.18内核的源代码中,可以在其内核源码树下include/asm-i386/unistd.h中找到这些BBdLinux联盟
BBdLinux联盟
宏定义:BBdLinux联盟
#define __syscall_return(type, res) \BBdLinux联盟
do { \BBdLinux联盟
        if ((unsigned long)(res) >= (unsigned long)(-125)) { \BBdLinux联盟
                errno = -(res); \BBdLinux联盟
                res = -1; \BBdLinux联盟
        } \BBdLinux联盟
        return (type) (res); \BBdLinux联盟
} while (0)BBdLinux联盟
BBdLinux联盟
#define _syscall0(type,name) \BBdLinux联盟
type name(void) \BBdLinux联盟
{ \BBdLinux联盟
long __res; \BBdLinux联盟
__asm__ volatile ("int $0x80" \BBdLinux联盟
        : "=a" (__res) \BBdLinux联盟
        : "0" (__NR_##name)); \BBdLinux联盟
__syscall_return(type,__res); \BBdLinux联盟
}BBdLinux联盟
BBdLinux联盟
#define _syscall1(type,name,type1,arg1) \BBdLinux联盟
type name(type1 arg1) \BBdLinux联盟
{ \BBdLinux联盟
long __res; \BBdLinux联盟
__asm__ volatile ("int $0x80" \BBdLinux联盟
        : "=a" (__res) \BBdLinux联盟
        : "0" (__NR_##name),"b" ((long)(arg1))); \BBdLinux联盟
__syscall_return(type,__res); \BBdLinux联盟
}BBdLinux联盟
BBdLinux联盟
#define _syscall2(type,name,type1,arg1,type2,arg2) \BBdLinux联盟
type name(type1 arg1,type2 arg2) \BBdLinux联盟
{ \BBdLinux联盟
long __res; \BBdLinux联盟
__asm__ volatile ("int $0x80" \BBdLinux联盟
        : "=a" (__res) \BBdLinux联盟
        : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \BBdLinux联盟
__syscall_return(type,__res); \BBdLinux联盟
}BBdLinux联盟
BBdLinux联盟
BBdLinux联盟
BBdLinux联盟
将这些代码copy到你自己的$SRC/include/asm-i386/unistd.h(我在实际中去掉了所有宏BBdLinux联盟
BBdLinux联盟
BBdLinux联盟
包含变量errno的一行,因为在我们的代码中没有这个变量的定义,即使你在其中加入BBdLinux联盟
extern int errno;BBdLinux联盟
在编译没问题,链接也会有问题的,试试就知道了,如果非要使用errno,那就自己专研吧BBdLinux联盟
BBdLinux联盟
,呵呵!)BBdLinux联盟
BBdLinux联盟
6 所有准备工作完成,现在就是编译新内核了(可能有人会提到将这个系统调用以模块方BBdLinux联盟
BBdLinux联盟
式加载就不用重新BBdLinux联盟
编译内核了,想法是好的,但是考虑到安全问题,不知道是从什么版本开始,已经取消了BBdLinux联盟
BBdLinux联盟
对系统调用表BBdLinux联盟
sys_call_table的导出,所以你在模块中是没法访问系统调用表的,当然也可以通过其他BBdLinux联盟
BBdLinux联盟
途径来完成这个任务BBdLinux联盟
,不过那是hacker们的办法了,这里不加讨论)BBdLinux联盟
在$SRC中BBdLinux联盟
make menuconfigBBdLinux联盟
make BBdLinux联盟
make installBBdLinux联盟
即可,在2.6中已经对编译内核的方法简化了许多,不需要以前对依赖关系的检查了,新的BBdLinux联盟
BBdLinux联盟
Makefile帮助完成这些工作了。BBdLinux联盟
在make install中已经帮你完成了BBdLinux联盟
(1)将新内核镜像bzImage拷贝到/boot/vmlinuz-verisonBBdLinux联盟
(2)构建新的initrd-version.img文件BBdLinux联盟
(3)创建新的内核符号表System.map(这个文件不是内核启动必须的,一般调试用)BBdLinux联盟
(4)修改你的grub或者lilo启动文件BBdLinux联盟
所以你只需要reboot就可以看到你新编译的内核了。至于内核的配置和vmlinuz和initrd2BBdLinux联盟
BBdLinux联盟
个文件各自的用处,大家可以上网查询,这里BBdLinux联盟
不详细介绍了。如果你的新内核无法启动,多半是initrd出了问题(简单的说下initrd文BBdLinux联盟
BBdLinux联盟
件包含了你的内核在加载文件系统前的一些驱动程序BBdLinux联盟
比如硬盘驱动,ext3文件系统的驱动等等,如果这些有问题,内核是无法启动的,网上说BBdLinux联盟
BBdLinux联盟
可以把这些一起编译到内核vmlinuz中而不需要initrd,BBdLinux联盟
大家可以去试试)BBdLinux联盟
7 现在新内核启动起来了,我们写一个用户测试程序mysyscall.c使用我们新的系统调用吧BBdLinux联盟
BBdLinux联盟
BBdLinux联盟
#include <linux/unistd.h>BBdLinux联盟
#include <stdio.h>BBdLinux联盟
#include <sys/types.h>BBdLinux联盟
#include <fcntl.h>BBdLinux联盟
#include <sys/stat.h>BBdLinux联盟
#define __NR_mysyscall 318BBdLinux联盟
_syscall0(int,mysyscall)BBdLinux联盟
int main()BBdLinux联盟
{BBdLinux联盟
        printf("before, my euid is: %d!\n",geteuid());BBdLinux联盟
        if(open("/etc/shadow",O_RDONLY)<0)BBdLinux联盟
                printf("open failed!\n");BBdLinux联盟
BBdLinux联盟
        mysyscall();BBdLinux联盟
printf("after, my euid is %d!\n",geteuid());BBdLinux联盟
        if(open("/etc/shadow",O_RDONLY)>0)BBdLinux联盟
                printf("open succeed!\n");BBdLinux联盟
       BBdLinux联盟
        return 0;BBdLinux联盟
}BBdLinux联盟
在普通用户下运行该程序BBdLinux联盟
before, my euid is: 500!BBdLinux联盟
open failed!BBdLinux联盟
after, my euid is 0!BBdLinux联盟
open succeed!BBdLinux联盟
BBdLinux联盟
发现居然可以访问本来只有root能访问的shadown文件了 o(∩_∩)o!BBdLinux联盟
欢迎大家讨论!BBdLinux联盟
来顶一下
近回首页
返回首页
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
相关文章
栏目更新
栏目热门