使用copy_*_user 函数族传递带有指针的结构体

使用copy_*_user 函数族传递带有指针的结构体

在调试代码时出现内核奔溃的问题,提示使用了用户空间地址,查下来发现是使用copy_from_user将用户空间的结构体传递到了内核中去,但是程序运行后发现使用copy_from_user接收到的结构体在使用时发生内核崩溃打印提示是使用了用户空间的地址的原因,看了下发现了问题

我们使用copy_*_user 函数族 的原因是在linux中将内存分为用户空间(0-3G)内核空间(3-4G),使用的这个函数就是将存在于用户空间的数据复制到内核空间进行修改再传回用户空间去,但是这里会出现个问题,那就是unsigned long *copy_from_user*(void * to, const void __user * from, unsigned long n)我们根据这个函数的原型可以知道这里我们其实是根据用户空间传过来的地址将这个地址内的数据复制到内核空间去的,但是当你传的是个指针的话,使用ioctrl将数据传入内核的时候实际上只是将这个指针所指向的地址传入了内核,并没有将指针指向地址的内存复制到内核,譬如

struct my_struct {
    int a;
    char *b;
};
struct my_struct user;
// user spaces
ioctrl(cmd, (void *)&user, sizeof(struct my_struct));

//kernel spces
struct my_struct ker;
copy_from_user((void *)ker, (void *)arg, sizeof(struct my_struct));

这个时候其实就会出现问题了,首先这个结构体成员中的int类型的参数a是很正常的复制到了内核空间去,但是这个指针类型char其实这个时候只是把这个指针的地址复制到了内核空间,也就是说ker.b他指向的还是一个用户空间的内存地址,如果这个时候你解引用的话还是会直接调用到用户空间,那解决这个问题的办法就是要不你不要传入指针,要不就是再对这个地址进行一次copy_from_user

struct my_struct {
    int a;
    char *b;
};
struct my_struct user;
// user spaces
ioctrl(cmd, (void *)&user, sizeof(struct my_struct));

//kernel spces
struct my_struct ker;
char c;
copy_from_user((void *)&ker, (void *)arg, sizeof(struct my_struct));
copy_from_user((void *)&c, (void *)ker.b, sizeof(char *));	//将指针指向的地址复制到内核空间
ker.b = &c;

同理当你需要将这个结构体传回用户空间时也是需要分两步传上去

这里需要在传下来的时候将传下来的那个用户空间地址先保存下来

struct my_struct {
    int a;
    char *b;
};
struct my_struct user;
// user spaces
ioctrl(cmd, (void *)&user, sizeof(struct my_struct));

//kernel spces
struct my_struct ker;
char c;
__user char *d;
copy_from_user((void *)&ker, (void *)arg, sizeof(struct my_struct));
d = ker.b;	//将传下来的用户空间地址保存起来
copy_from_user((void *)&c, (void *)ker.b, sizeof(char));	//将指针指向的地址复制到内核空间
ker.b = &c;

//to user spaces
copy_to_user((void *)d, (void *)&c, sizeof(char));
copy_to_user((void *)arg, (void *)&ker, sizeof(struct my_struct));

以上是本人开发过程中遇到的问题,并自己给出了解决方法,如果有人的方法比我简洁易懂,欢迎评论区指出,我会虚心学习的b( ̄▽ ̄)d

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Linux内核中,文件操作是通过结构体`file_operations`来实现的,其中包括了一系列函数指针,用于实现文件的读、写、打开、关闭等操作。其中,read函数函数指针名为`read`,其定义如下: ``` ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ``` read函数的参数包括: - `struct file * filp`:表示要读取的文件对象; - `char __user * buf`:表示读取缓冲区的地址,即将文件数据读取到哪里; - `size_t count`:表示要读取的字节数; - `loff_t *f_pos`:表示读取的起始位置,即从文件的哪个位置开始读取。 read函数的返回值为`ssize_t`类型,表示实际读取的字节数。如果返回值为0,则表示已经读取到了文件末尾;如果返回值为负数,则表示读取出错。 在Linux内核中,read函数主要用于读取设备文件的数据,因此可以通过实现read函数来实现设备文件的读取操作。通常情况下,read函数的实现涉及到文件操作锁的处理、文件指针的移动、数据的拷贝等操作。以下是一个简单的read函数的实现示例: ```c static ssize_t my_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { int ret = 0; /* 获取锁 */ if (down_interruptible(&dev->sem)) return -ERESTARTSYS; /* 判断读取位置是否超出文件末尾 */ if (*f_pos >= dev->size) goto out; /* 计算实际需要读取的字节数 */ if (*f_pos + count > dev->size) count = dev->size - *f_pos; /* 从设备中读取数据 */ ret = copy_to_user(buf, (void*)(dev->data + *f_pos), count); if (ret != 0) { ret = -EFAULT; goto out; } /* 更新文件指针 */ *f_pos += count; ret = count; out: /* 释放锁 */ up(&dev->sem); return ret; } ``` 该函数首先获取了文件操作锁,然后判断读取位置是否超出了文件末尾,接着计算实际需要读取的字节数。最后,从设备中读取数据,并更新文件指针,最终释放锁并返回读取的字节数。需要注意的是,该示例仅供参考,实际情况下需要根据具体需求进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Enosji

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值