当前位置:Linux教程 - Linux - Linux 可卸载内核模块完全指南之四

Linux 可卸载内核模块完全指南之四



        
    the definitive guide for hackers, virus coders and system administrators
    (作者:pragmatic/THC,(版本1.0) 2000年05月16日 16:44)


    1.5使用用户空间函数的方法


    正如你在1.4中看到的我们利用一个syscall宏来构造我们自己的brk调用,就像我们从用户空间中调用一样,实际上那些用户空间的很多库函数(并不是所有的)都是通过这种syscall宏调用实现的,下面的代码显示了在1.4中调用的_syscall1(.....)宏。(摘自/asm/unistd.h)

    #define _syscall1(type,name,type1,arg1) \\

    type name(type1 arg1) \\

    { \\

    long __res; \\

    __asm__ volatile (\"int $0x80\" \\

    : \"=a\" (__res) \\

    : \"0\" (__NR_##name),\"b\" ((long)(arg1))); \\

    if (__res >= 0) \\

    return (type) __res; \\

    errno = -__res; \\

    return -1; \\

    }



    你并不需要理解这个函数的全部代码.他不过是调用中断0x80并把_syscall提供的参数(->1.2)传进去.name表示我们所需要的系统调用.(name被展开为__NR_name,这是在/asm/unistd.h中定义的).通过这个方法我们实现了brk函数.其他的拥有不同数量参数的函数通过其他的一些宏实现(_syscallX,X代表参数的个数).我个人用另一种方法来实现这个函数,看下面的例子:



    int (*open)(char *, int, int);

    /*声明一个函数原型*/



    open = sys_call_table[SYS_open];

    /*你也可以用__NR_open*/



    在这个方法中你并不需要使用任何syscall宏,你只需要使用sys_call_table中的函数指针就可以了.在网上,我发现这种构造用户空间函数的方法也被SVAT的著名的LKM传播者使用.依我的观点,这种方法是好一些的方法.但是你应该测试并且做出自己的判断.



    当提供参数给这些系统调用时你要小心,他们需要这些参数在用户空间,而不是内核空间.阅读1.4来找到从内核空间拷贝到用户空间的方法.



    一个很简单的实现这个的方法(在我看来是最好的方法)就是利用所需的寄存器.你必须知道linux通过利用段选择器来区别用户空间,系统空间等等.系统调用使用的参数都是通过数据段(DS)来寻址的.(我没有在1.4中提到这些,因为我觉得放在这里更合适)



    DS可以通过asm/segment.h中的get_ds()获得.因此如果我们设置段选择器为一个合适的值,我们就可以直接获得系统调用的参数.设置段选择器可以用set_fs(....)实现.但是要小心,在你获得系统调用的参数以后必须恢复FS的值.OK,现在让我们来看一段有用的代码:



    ->filename 是在我们的内核空间;比如说,一个我们刚刚创建的字符串



    unsigned long old_fs_value=get_fs();



    set_fs(get_ds);      

    /*从这以后我们可以存取用户空间的数据*/



    open(filename, O_CREAT|O_RDWR|O_EXCL, 0640);



    set_fs(old_fs_value);    

    /*恢复fs.....*/



    在我看来,这是最简单也是最好的解决这个问题的方法.但是你必须亲自测试他(再一次:P).记住到目前为止我演示的几个函数(brk,open)都是通过很简单的系统调用实现的.你可以看一眼我们感兴趣那些系统调用列表(1.2);比如说,sys_socketcall和所有对sockets的操作的实现有关(创建,关闭,发送,接收......).因此在创建你自己的函数时要十分的小心.要常常看一看内核的源代码.



    1.6常用内核空间函数列表


    在本文开始的时候我介绍过printk(....)函数.那是一个每个人在内核空间都可以使用的函数,可以叫做内核函数.这些函数是给那些需要复杂函数的内核开发者的,常常由一些库提供.下面的表列出了一些最为重要的我们常使用的函数:



    函数/宏 描述



    int sprintf (char *buf, const char *fmt, ...);

    int vsprintf (char *buf, const char *fmt, va_list args);

    用来格式化字符串的函数



    printk (...)

    与用户空间的printf一样



    void *memset (void *s, char c, size_t count);

    void *memcpy (void *dest, const void *src, size_t count);

    char *bcopy (const char *src, char *dest, int count);

    void *memmove (void *dest, const void *src, size_t count);

    int memcmp (const void *cs, const void *ct, size_t count);

    void *memscan (void *addr, unsigned char c, size_t size);

    内存函数



    int register_symtab (struct symbol_table *intab); see I.1

    char *strcpy (char *dest, const char *src);

    char *strncpy (char *dest, const char *src, size_t count);

    char *strcat (char *dest, const char *src);

    char *strncat (char *dest, const char *src, size_t count);

    int strcmp (const char *cs, const char *ct);

    int strncmp (const char *cs,const char *ct, size_t count);

    char *strchr (const char *s, char c);

    size_t strlen (const char *s);

    size_t strnlen (const char *s, size_t count);

    size_t strspn (const char *s, const char *accept);

    char *strpbrk (const char *cs, const char *ct);

    char *strtok (char *s, const char *ct);

    字符串比较等操作的函数



    unsigned long simple_strtoul (const char *cp, char **endp, unsigned int base);

    将字符串转换成数字



    get_user_byte (addr);

    put_user_byte (x, addr);

    get_user_word (addr);

    put_user_word (x, addr);

    get_user_long (addr);

    put_user_long (x, addr);

    用来访问用户内存的函数



    suser();

    fsuser();

    检查超级用户权限的



    int register_chrdev (unsigned int major, const char *name, struct file_o perations *fops);

    int unregister_chrdev (unsigned int major, const char *name);

    int register_blkdev (unsigned int major, const char *name, struct file_o perations *fops);

    int unregister_blkdev (unsigned int major, const char *name);

    注册设备驱动的函数

    ..._chrdev -> 字符设备

    ..._blkdev -> 块设备



    请记住这里的一些函数也可以通过1.5中提到的方法使用.但是你必须明白,当内核无偿提供了这些函数时,通过用户空间函数来使用他们没有什么意义.



    随后你会看到这些函数(特别是字符串比较函数)很重要的应用.
    发布人:netbull 来自:Linux中文资料