LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1120|回复: 8

核心如何使用用户空间的参数

[复制链接]
发表于 2005-5-31 16:03:02 | 显示全部楼层 |阅读模式
当一个系统调用发生时  系统调用通过寄存器向内核传递参数  并将这些参数保存到内核堆栈中
但现在我的问题是  向内核传递的参数有些只是一个指向用户空间的指针 比如
asmlinkage int sys_open(const char * filename, int flags, int mode)
这时在进入内核后是如何访问到这些参数的
本人猜想是不是这样 用户态和核心态使用的DS中段选择子描述的段地址是一样的(都是0x00000000),它们可以直接使用参数的。
发表于 2005-5-31 16:12:53 | 显示全部楼层
Post by qqrilxk
当一个系统调用发生时  系统调用通过寄存器向内核传递参数  并将这些参数保存到内核堆栈中
但现在我的问题是  向内核传递的参数有些只是一个指向用户空间的指针 比如
asmlinkage int sys_open(const char * filename, int flags, int mode)
这时在进入内核后是如何访问到这些参数的
本人猜想是不是这样 用户态和核心态使用的DS中段选择子描述的段地址是一样的(都是0x00000000),它们可以直接使用参数的。

段基地址确实是一样的,
不知道你说的直接使用是什么意思,内核当然是从内核栈中取得参数,对于那些指针,内核则会先将数据拷贝的内核,然后再操作这些数据.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-5-31 18:02:21 | 显示全部楼层
楼上大哥 想问一下  那现在本人在内核中想根椐那些参数指针得到这些参数该怎么做呀  你说的先将数据拷贝到内核这是怎样完成的呀 即然它们在同一个DS中那可不可以就像(*reference)一样直接使用呀 可能不行吧 这又是为什么了
看了一下sys_open不太懂呀
asmlinkage long sys_open(const char __user * filename, int flags, int mode)
{
        char * tmp;
        int fd, error;

#if BITS_PER_LONG != 32
        flags |= O_LARGEFILE;
#endif
        tmp = getname(filename);
        fd = PTR_ERR(tmp);
        if (!IS_ERR(tmp)) {
                fd = get_unused_fd();
                if (fd >= 0) {
                        struct file *f = filp_open(tmp, flags, mode);
                        error = PTR_ERR(f);
                        if (IS_ERR(f))
                                goto out_error;
                        fd_install(fd, f);
                }
out:
                putname(tmp);
        }
        return fd;

out_error:
        put_unused_fd(fd);
        fd = error;
        goto out;
}
在其中用到了getname
char * getname(const char __user * filename)
{
        char *tmp, *result;

        result = ERR_PTR(-ENOMEM);
        tmp = __getname();
        if (tmp)  {
                int retval = do_getname(filename, tmp);

                result = tmp;
                if (retval < 0) {
                        __putname(tmp);
                        result = ERR_PTR(retval);
                }
        }
        if (unlikely(current->audit_context) && !IS_ERR(result) && result)
                audit_getname(result);
        return result;
}
也看了半天不懂 好心大哥能否给个解释呀  谢谢
本人想根据这参数指针在内核中得到参数能否就在使用getname吗  谢谢
回复 支持 反对

使用道具 举报

发表于 2005-5-31 19:04:00 | 显示全部楼层
Post by qqrilxk
楼上大哥 想问一下  那现在本人在内核中想根椐那些参数指针得到这些参数该怎么做呀  你说的先将数据拷贝到内核这是怎样完成的呀 即然它们在同一个DS中那可不可以就像(*reference)一样直接使用呀 可能不行吧 这又是为什么了

不在同一个ds下,只是ds基址与段界限相同.
Post by qqrilxk

char * getname(const char __user * filename)
{
        char *tmp, *result;

        result = ERR_PTR(-ENOMEM);
        tmp = __getname();
        if (tmp)  {
                int retval = do_getname(filename, tmp);

                result = tmp;
                if (retval < 0) {
                        __putname(tmp);
                        result = ERR_PTR(retval);
                }
        }
        if (unlikely(current->audit_context) && !IS_ERR(result) && result)
                audit_getname(result);
        return result;
}

看下面这个函数,第125行
    114 static inline int do_getname(const char __user *filename, char *page)
    115 {
    116     int retval;
    117     unsigned long len = PATH_MAX;
    118
    119     if ((unsigned long) filename >= TASK_SIZE) {
    120         if (!segment_eq(get_fs(), KERNEL_DS))
    121             return -EFAULT;
    122     } else if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
    123         len = TASK_SIZE - (unsigned long) filename;
    124
    125     retval = strncpy_from_user((char *)page, filename, len);
    126     if (retval > 0) {
    127         if (retval < len)
    128             return 0;
    129         return -ENAMETOOLONG;
    130     } else if (!retval)
    131         retval = -ENOENT;
    132     return retval;
    133 }
回复 支持 反对

使用道具 举报

发表于 2005-6-8 10:56:01 | 显示全部楼层
你确实试过不能访问吗?
当你的进程调用了系统调用而进入内核空间的时候,CR3并不改变,也就是说进入内核态以后使用的还是原来进程的页表,而用户空间的也表权限都是设成低的,也就是内核态可以访问的,所以我觉得直接读取应该也没有问题
回复 支持 反对

使用道具 举报

发表于 2005-6-8 11:53:57 | 显示全部楼层
Post by xieweiyi
你确实试过不能访问吗?
当你的进程调用了系统调用而进入内核空间的时候,CR3并不改变,也就是说进入内核态以后使用的还是原来进程的页表,而用户空间的也表权限都是设成低的,也就是内核态可以访问的,所以我觉得直接读取应该也没有问题

xieweiyi兄说得对

像strncpy_from_user等等其实也只是相当于一个memcpy的功能,也是直接读写内存的
回复 支持 反对

使用道具 举报

发表于 2005-6-9 16:37:18 | 显示全部楼层
Post by xieweiyi
你确实试过不能访问吗?
当你的进程调用了系统调用而进入内核空间的时候,CR3并不改变,也就是说进入内核态以后使用的还是原来进程的页表,而用户空间的也表权限都是设成低的,也就是内核态可以访问的,所以我觉得直接读取应该也没有问题

不是不能访问,更多的是出于安全考虑吧,如果随便使用用户提供的参数不加验证,系统是很容易崩溃的.
回复 支持 反对

使用道具 举报

发表于 2005-6-11 16:44:02 | 显示全部楼层
验不验证和能不能访问没有关系吧,就算要验证,也要访问以后再验证吧,这两者似乎不存在什么关系啊
回复 支持 反对

使用道具 举报

发表于 2005-6-21 03:48:29 | 显示全部楼层
以前的内核是有个verify_area()函数的,有参数可以对读或写分别作检验,对用户态传入的地址作可读或可写检验。
但大量测试表明就是这个读写检验浪费时间较多,从2.4版中引入了一种exception方式,假定用户传入的指针都是有效的,万一有个无效的指针传进来再跳入exception段执行。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表