RK android 系统32位,kernel 64位导致copy_from_user传参数异常

具体细节:

定义了以下结构体

typedef struct {
    void *pInBuf;
    int InSize;
    void *pOutBuf;
    int OutSize;
} sParams;

android hidl 层 定义了参数 sParams tmpBuf, pInBuf以及pOutBuf 保存缓存数据的地址,InSize以及OutSize保存缓存数据的大小 例:

int InVal = 25;
int OutVal[3] = {0,1,2};

sParams tmpBuf;
tmpBuf.pInBuf = &InVal;
tmpBuf.InSize = sizeof(InVal);

tmpBuf.pOutBuf = OutVal;
tmpBuf.OutSize = sizeof(OutVal);

 android hidl 通过 ioctl(fd, cmd , &tmpBuf) 把 tmpBuf 参数的地址传入内核

内核驱动的 ioctl的内部实现 通过 copy_from_user 拿到tmpBuf的数据,再通过pInBuf以及pOutBuf的地址调用 copy_from_user 拿到缓存对应的数据 例:

内核的 ioctl内部实现:

custom_ioctl(struct file *filp , unsigned int cmd, unsigned long arg)
{
    void *pInBuf;
    void *pOutBuf;
    sParams tmp;

    copy_from_user((void*)&tmp, (void*)arg, sizeof(sParams));
    //获取上层tmpBuf 参数初始化 参数:tmp

    pInBuf = tmp.pInBuf;
    pOutBuf = tmp.pOutBuf;
    
    tmp.pInBuf = kzalloc(tmp.InSize, GFP_KERNEL);
    copy_from_user(tmp.pInBuf, pInBuf, tmp.InSize);
    //获取缓存pInBuf:InVal的数据

    tmp.pOutBuf = kzalloc(tmp.OutSize, GFP_KERNEL);
    copy_from_user(tmp.pOutBuf, pOutBuf, tmp.OutSize);
    //获取缓存pOutBuf:OutVal[3] 的数据
}

 异常点:

1.copy_from_user((void*)&tmp, (void*)arg, sizeof(sParams));

内核 64位系统而android是32位系统 指针的大小是不一致的导致sizeof(sParams)的大小与 android hidl 层 sizeof(sParams)的大小不一致,arg参数就算是上层tmpBuf的地址,但是由于对指针的大小计算不一致会导致 copy_from_user的数据出异常

解决办法:

typedef struct {
    uint32_t pInBuf;
    int InSize;
    uint32_t pOutBuf;
    int OutSize;
} sParams;

地址 void* 改为 uint32_t (android 系统32位)hidl 在对tmpBuf赋值时修改为:

tmpBuf.pInBuf = (uint32_t) &InVal,tmpBuf.pOutBuf = (uint32_t)(&OutVal[0]);

驱动层在调用

copy_from_user((void*)&tmp, (void*)arg, sizeof(sParams));

这个时候的sizeof(sParams)大小与 android 32位系统的计算大小一致,拷贝就不会出问题

2   拿到 缓存地址 pInBuf以及pOutBuf 后copy_from_user异常

修复异常1的问题后驱动层可以正确拿到 android hidl层通过ioctl 传递的tmpBuf的数据,

tmp.pInBuf 与 tmpBuf.pInBuf ,tmp.pOutBuf与 tmpBuf.pOutBuf的数值一致,但是

以下拷贝缓存数据的操作仍存在异常

tmp.pInBuf = kzalloc(tmp.InSize, GFP_KERNEL);

//在内核申请缓存用于保存上层缓存数据
 copy_from_user(tmp.pInBuf, pInBuf, tmp.InSize);
 //获取缓存pInBuf:InVal的数据

android的tmpBuf.pInBuf 通过copy_from_user 赋值给了内核的tmp.pInBuf,但是tmp.pInBuf是uint32_t类型 kernel 层的指针是 64的,数据拷贝时需做以下改动:

    void *pInBuf;
    void *pOutBuf;
   

    pInBuf = (void*)(long)tmp.pInBuf;
    pOutBuf = (void*)(long)tmp.pOutBuf;
    
    tmp.pInBuf = kzalloc(tmp.InSize, GFP_KERNEL);
    copy_from_user(tmp.pInBuf, pInBuf, tmp.InSize);
    //获取缓存pInBuf:InVal的数据

    tmp.pOutBuf = kzalloc(tmp.OutSize, GFP_KERNEL);
    copy_from_user(tmp.pOutBuf, pOutBuf, tmp.OutSize);
    //获取缓存pOutBuf:OutVal[3] 的数据

(void*)(long)tmp.pInBuf 先通过 (long )让32位变为64位,再通过 (void*)转为地址,

最终copy_from_user 可以正确拿到android的 InVal以及OutVal[3]的所有数据

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

猿-源

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

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

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

打赏作者

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

抵扣说明:

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

余额充值