什么是使用Linuxmacrosaccess_ok()

我一直在做一些研究,我对这个macros有点困惑。 希望有人能给我一些指导。 我有一些ioctl代码(我已经inheritance,没有写),如果在从用户空间复制数据之前检查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返回的描述:

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

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

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

  • types参数可以指定为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; \ }) 

Solutions Collecting From Web of "什么是使用Linuxmacrosaccess_ok()"

如果__lddk_copy_from_user()简单地调用copy_from_user() ,那么access_ok()检查是多余的,因为copy_from_user()自己执行这些检查。

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

另外,用VERIFY_WRITE调用access_ok()意味着VERIFY_READ ,所以如果你检查前者,你也不需要检查后者。

access_ok宏只是快速检查指针可能的有效性。 例如,它会用NULL或只读参数来捕获错误的调用。

理想情况下,即使后来访问功能失败,驱动程序也应该恢复。 然而这只能在昂贵的硬件操作之后才能发生。 因此,尽早检查可能会使驱动程序对最常见的用户空间程序员错误更加健壮。

编辑:是的,如果你唯一的输入调用是copy_from_user()那里,检查是多余的。 但是,如果稍后写入,则在开始时检查可写性是非常有用的。

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

这不是多余的。 access_ok()验证地址,试图从这个区域读取。 如果地址有效并存在于用户空间中,则尝试读取,否则该函数返回EFAULT,这表示地址失败。 这是一个更安全的方式来验证区域的访问,而不是检查NULL(在出现任何可能导致内核崩溃的分段错误之前)。

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