编辑:关于为什么我在这里失败了,我还没有一个好的答案......所以让我重新表述一下。我什至需要 verify_area() 检查吗?那有什么意义呢?我已经测试了我的结构成功传递给这个 ioctl 的事实,我正在考虑只是删除失败的检查,但我不是 100% 它在那里做的事情。想法? 结束编辑
我正在努力更新一些较旧的 linux 内核驱动程序,在测试一个时我遇到了一个失败,这对我来说似乎很奇怪。开始了:
我在用户空间有一个简单的 ioctl 调用:
Config_par_t cfg;
int ret;
cfg.target = CONF_TIMING;
cfg.val1 = nBaud;
ret = ioctl(fd, CAN_CONFIG, &cfg);
Config_par_t 定义在 can4linux.h 文件中(这是 uCLinux 自带的 CAN 驱动):
typedef struct Command_par {
int cmd; /**< special driver command */
int target; /**< special configuration target */
unsigned long val1; /**< 1. parameter for the target */
unsigned long val2; /**< 2. parameter for the target */
int error; /**< return value */
unsigned long retval; /**< return value */
} Command_par_t ;
在内核方面,ioctl 函数调用 verify_area,这是失败的过程:
long can_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void *argp;
long retval = -EIO;
Message_par_t Message;
Command_par_t Command;
struct inode *inode = file->f_path.dentry->d_inode;
argp = &Message;
Can_errno = 0;
switch(cmd) {
case CONFIG:
if( verify_area(VERIFY_READ, (void *) arg, sizeof(Command_par_t))) {
return(retval);
}
现在我知道 verify_area() 不再使用了,所以我在头文件中用这个宏将它更新为 access_ok:
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
#define verify_area(type, addr, size) access_ok(type, addr, size)
#endif
我在 x86 平台上,所以我很确定实际调用的 access_ok() 宏是 /usr/src/linux/arch/x86/include/asm/uaccess.h 中定义的宏:
#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0))
#define __range_not_ok(addr, size) \
({ \
unsigned long flag, roksum; \
__chk_user_ptr(addr); \
asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \
: "=&r" (flag), "=r" (roksum) \
: "1" (addr), "g" ((long)(size)), \
"rm" (current_thread_info()->addr_limit.seg)); \
flag; \
})
我想对我来说这看起来应该可以工作。如果检查,为什么我从这个 verify_area 得到 1 回报的任何想法?或者关于如何缩小问题范围的任何想法?
if( verify_area(VERIFY_READ, (void *) arg, sizeof(Command_par_t))) {