使用linux宏access_ok()有什么意义

Mik*_*ike 7 c linux macros ioctl linux-kernel

我一直在做一些研究,我对这个宏有点困惑.希望有人可以给我一些指导.我有一些ioctl代码(我继承了,没有编写),如果access_ok()在继续从用户空间复制数据之前检查是否它会做的第一件事:

#define __lddk_copy_from_user(a,b,c) copy_from_user(a,b,c)
#define __lddk_copy_to_user(a,b,c) copy_to_user(a,b,c)

long can_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
  switch(cmd) {
    case COMMAND:
      if(! access_ok(VERIFY_READ, (void *)arg, sizeof(Message_par_t)))
        return(retval); 

      if(! access_ok(VERIFY_WRITE, (void *)arg, sizeof(Message_par_t)))
        return(retval); 

      argp = &Command;
      __lddk_copy_from_user( (void *) argp,(Command_par_t *) arg, sizeof(Command_par_t));
Run Code Online (Sandbox Code Playgroud)

所以代码工作正常,但我不确定它是否需要.第一个问题来自access_ok的返回描述:

  • 如果该区域可能可访问,则该函数返回非零(尽管访问仍可能导致-EFAULT).此函数只检查地址是否可能在用户空间中,而不是在内核中.

所以这意味着它真的什么都没做,那么确保我们检查的指针可能在用户空间中被初始化了?既然我们知道除了用户空间调用之外我们不能进入这个功能,除非我们为这个设备打开一个有效的文件描述符,否则它不会发生,这真的需要吗?它确实比确保我们没有得到NULL指针更安全吗?

第二个问题来自这个描述:

  • type参数可以指定为VERIFY_READ或VERIFY_WRITE.VERIFY_WRITE符号还标识内存区域是可读还是可写.

这是否意味着我的代码中的第一次检查是多余的?如果我们要检查可写区域,我们可以作为免费赠品阅读吗?

我正在使用x86架构,所以access_ok()和__range_no_ok()的定义来自/usr/src/linux-3.1.10-1.16/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;                               \
})
Run Code Online (Sandbox Code Playgroud)

caf*_*caf 12

如果__lddk_copy_from_user()只是调用copy_from_user(),那么access_ok()检查是多余的,因为copy_from_user()它们自己执行这些检查.

access_ok()检查确保用户空间应用程序不要求内核读取或写入内核地址(他们的完整性/安全性检查).仅仅因为用户空间提供的指针并不意味着它肯定是用户空间指针 - 在许多情况下"内核指针"只是意味着它指向虚拟地址空间的特定区域.

另外,access_ok()使用VERIFY_WRITE暗示调用VERIFY_READ,所以如果你检查前者,你也不需要检查后者.


截至2019年这个提交,access_ok()没有多久的type论点,所以VERIFY_WRITEVERIFY_READ点是没有实际意义的.