copy_to/from_user与put/get_user多做了什么?
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
{
if (likely(access_ok(VERIFY_WRITE, to, n)))
n = __copy_to_user(to, from, n);
return n;
}
以上函数都是linux内核推荐在内核中使用与用户空间交互的函数。那么为啥不能直接使用memcpy?
1.access_ok
在以上函数中都使用到了access_ok,而这个函数能够判断用户空间传入的地址是否来自用户空间(即不来自内核空间)
但是这个函数不能判断该地址是否为NULL/0,也就是说如果用户空间传入空指针,那么也是来自用户空间的。
这避免了用户空间操作内核空间地址的可能性。
2.判断是否为野指针或者空指针
如果是那么就把改指针指向的地址值赋值为空,然后退出。这避免了内核Oops因为,如果在内核空间发生
Segmentation fault(段错误),那么会引起Oops,而如果是在用户空间发生段错误,那么内核会杀死这个进程。
但是同样会触发Segmentation fault。
总结:
1.阻止用户空间使用内核空间地址(如果用户进程在自己进程中访问内核地址会引发段错误,但是,不访问就不会出错,所以可以传给内核空间,进而内核空间要进行判断)
2.避免用户空间的段错误引起内核Oops或者Panic。(但是同样会利用段错误杀手用户进程)
我的实验:
内核空间:
ssize_t led_read(struct file *filp, char __user *buf, size_t size, loff_t *offset)
{
char *data = "hello";
if(!access_ok(VERIFY_WRITE,buf,strlen(data)))
printk("access_not_ok\n",buf);
printk("buf is %p",buf);
//copy_to_user(buf, data, strlen(data));
//printk("buf is %p\n",buf);
memcpy(buf, data, strlen(data));
return 0;
}
用户空间:
int main(int argc,char **argv)
{
int fd = 0;
char *data=0x9999999999999999999;
if(argc!=2)
{
printf("argc error!\n");
return -1;
}
fd = open(argv[1],O_RDWR);
if(fd<0)
{
printf("open error!\n");
return -1;
}
//*data = 1;
//data = malloc(10*sizeof(char));
read(fd,data,10);
printf("buf is %p\n",data);
printf("data is %s\n",data);
//sleep(30);
close(fd);
}