什么是使用Linux宏观access_ok点()(What is the point of usin

2019-09-22 06:48发布

我一直在做一些研究,我有点困惑这个宏。 希望有人可以给我一些指导。 我有一些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));

因此,代码工作得很好,但我不知道它的需要。 第一个问题来自于access_ok的回归这样的描述:

  • 该函数返回非零值,如果该地区有可能访问(访问虽然仍可能导致-EFAULT)。 该功能只是简单地检查这个地址很可能在用户空间,而不是内核。

因此,这意味着它确实没有什么更多的则确保我们检查,对在用户空间可能是初始化指针? 因为我们知道,我们不能进入不是用户空间调用其它此功能,除非我们开了一个有效的文件描述符该设备可能不会发生,这是真正需要的? 难道真的更加安全则只是确保我们没有得到一个空指针?

第二个问题来自于这样的描述:

  • 类型参数可以被指定为VERIFY_READ或VERIFY_WRITE。 所述VERIFY_WRITE符号还识别所述存储区域是否可读以及可写的。

这是否意味着我的代码中的第一次检查是多余的? 如果我们要检查是否有可写的区域,我们得到可读的赠品?

我使用x86架构所以access_ok()和__range_no_ok()的definations是那些由/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;                               \
})

Answer 1:

如果__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点是没有实际意义。



Answer 2:

access_ok宏是只为指针的可能有效性的快速检查。 例如,它会赶上错电话与空或只读参数。

理想情况下,司机应收回,即使后来的访问功能失效。 这可能只是经过一些昂贵的硬件业务却发生了。 因此,早期检查可以使驾驶员对最常见的用户空间编程错误更稳健。

编辑:,是的,如果你唯一的输入调用是调用copy_from_user()那里,检查是多余的。 但是,如果有一个写以后,它是有用的检查可写正确的开头。

你真的应该检查调用copy_from_user的返回值()。



Answer 3:

这不是多余的。 access_ok()验证地址,尝试从该区域读取。 如果地址是有效的,在用户空间确实存在,那么就尝试读取,否则该函数返回EFAULT,它表示一个地址失败。 这是核实有关地区访问,而不是对空检查(你可能会导致你的内核崩溃任何分段故障前)更安全的方式。

此外,您可以验证读/写访问,使用access_ok()。 第二个电话只是验证在该区域“写入”权限。



文章来源: What is the point of using the linux macro access_ok()