1

編集:なぜここで失敗するのかについては、まだ良い答えがありません...それで、これを少し言い換えさせてください。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))) {
4

1 に答える 1

6

マクロは、ブロックが無効な場合access_okは 0 を返し、有効な可能性がある場合は 0 以外を返します。したがって、テストでは、ブロックが有効な場合はすぐに を返します。このように、次のように の結果を否定したい場合があります。-EIOaccess_ok

if (!access_ok(...))
于 2012-09-07T19:57:03.407 に答える