c - 为什么此 ioctl 的 access_ok 失败

标签 c linux macros ioctl uclinux

编辑: 关于我为什么会在这里失败,我还没有一个好的答案......所以让我稍微改一下。我什至需要 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))) {

最佳答案

access_ok 如果 block 无效 返回 0,如果可能有效则返回非零值。因此在您的测试中,如果该 block 有效,您将立即返回 -EIO。看起来,您可能想要否定 access_ok 的结果,例如:

if (!access_ok(...))

关于c - 为什么此 ioctl 的 access_ok 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12324522/

相关文章:

c++ - gcc 版本会影响 malloc 等功能吗?

rust - 具有相同分隔符的并排宏重复

c - 这个程序如何创建僵尸进程?

c - 在 C 中反转字符串中的单词

c - 为什么预定义宏 __STDC_VERSION__ 未定义?

macros - 为什么 clojure 向反引号内的名称添加 namespace 限定符?

c++ - 如何在多个平台上使用__FILE__和__LINE__ info实现C/C++可变参数记录宏?

c - C 和汇编中奇怪的变量问题

jquery - e.owlCarousel 不是 linux 主机上 yarn encore 生产后的功能

linux - psensors 和 gnome-system-monitor 的内存信息不同