使用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