(void __user *)arg 中__user的作用

本文详细介绍了在Linux环境下用户空间与内核空间之间的数据交互方式,特别是如何正确使用__user宏、copy_from_user及copy_to_user等函数来安全地进行数据交换。

__user宏简单告诉编译器(通过 noderef)不应该解除这个指针的引用(因为在当前地址空间中它是没有意义的)。 

 

(void __user *)arg 指的是arg值是一个用户空间的地址,不能直接进行拷贝等,要使用例如copy_from_user,copy_to_user等函数。

默认是内核空间,因为这是驱动,是在内核空间运行的。

 

直接拷贝不了,因为一个是在用户空间,一个是在内核空间

如果要拷贝的话,可使用 copy_from_user 


假如用户空间写为:

int i = 0;
ioctl(fd, XXXXX, i);


内核空间需要写为

get_user(xxx, (int __user *)arg);


假如用户空间写为:

int i = 0;
ioctl(fd, XXXXX, &i);

则内核空间需要写为:

copy_from_user(xxx, (void __user *)arg, size);

转载于:https://www.cnblogs.com/zl1991/p/6845751.html

在Linux驱动开发中,copy_from_user函数用于把用户空间的参数拷贝到内核空间,常应用于write之类的函数中[^2]。 ### 函数原型 ```c static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n); ``` 其中,`to` 是指向内核空间的目标地址指针,`from` 是指向用户空间的源地址指针,`n` 是要拷贝的字节数。 ### 使用示例 以下是一个简单的示例,展示如何使用 `copy_from_user` 将用户空间的数据复制到内核空间数组: ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/uaccess.h> #define BUFFER_SIZE 1024 static char kernel_buffer[BUFFER_SIZE]; static ssize_t my_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { unsigned long ret; if (count > BUFFER_SIZE) { count = BUFFER_SIZE; } ret = copy_from_user(kernel_buffer, buf, count); if (ret) { printk(KERN_ERR "Failed to copy data from user space\n"); return -EFAULT; } return count; } static struct file_operations my_fops = { .write = my_write, }; static int __init my_module_init(void) { register_chrdev(0, "my_device", &my_fops); return 0; } static void __exit my_module_exit(void) { unregister_chrdev(0, "my_device"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL"); ``` 在这个示例中,`my_write` 函数是字符设备驱动的写操作处理函数。当用户空间调用 `write` 系统调用时,`copy_from_user` 函数将用户空间缓冲区 `buf` 中的数据复制到内核空间数组 `kernel_buffer` 中。 ### 原理 `copy_from_user` 函数首先会调用 `access_ok(VERIFY_READ, from, n)` 检查用户空间地址是否合法。如果地址合法,则调用 `__copy_from_user` 函数进行实际的数据拷贝;如果地址不合法,为了避免安全漏洞,会将目标内核空间缓冲区清零[^2][^3]。 `__copy_from_user` 函数内部会调用 `might_sleep()` 表示该操作可能会睡眠,然后调用 `__copy_from_user_inatomic` 函数进行原子性的数据拷贝,最终通过 `memcpy` 完成实际的数据复制操作[^3]。 ### 可能出现的问题及解决办法 - **地址合法性问题**:如果用户空间地址不合法,`access_ok` 检查会失败,`copy_from_user` 可能会将内核空间缓冲区清零。解决办法是在调用 `copy_from_user` 之前,确保用户空间地址是有效的。 - **数据拷贝失败**:`copy_from_user` 函数返回值表示未成功拷贝的字节数。如果返回值不为 0,则表示数据拷贝失败。可以根据返回值进行错误处理,如返回错误码给用户空间。 - **睡眠问题**:由于 `copy_from_user` 操作可能会睡眠,因此不能在原子上下文(如中断处理程序)中使用。如果需要在原子上下文中进行数据拷贝,可以考虑使用 `__copy_from_user_inatomic` 函数,但需要确保用户空间地址的合法性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值