为什么 PTRACE_PEEKUSER 不允许读取 x86_64 上的 FPU 寄存器?

为什么 PTRACE_PEEKUSER 不允许读取 x86_64 上的 FPU 寄存器?

PTRACE_PEEKUSER被记录为从该区域读取一个单词user,其在 x86_64 上的部分布局是:

struct user
{
  struct user_regs_struct       regs;
  int                           u_fpvalid;
  struct user_fpregs_struct     i387;
  //...
  int                           u_debugreg [8];
};

虽然人们可以愉快地使用或PTRACE_PEEKUSER内的偏移量进行调用,但传递位于 内的偏移量会无条件返回。regsu_debugregi387EIO

查看内核中的代码,我可以看到内部读取的regsu_debugreg是唯一受支持的偏移量:

    case PTRACE_PEEKUSR: {
        unsigned long tmp;

        ret = -EIO;
        if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user))
            break;

        tmp = 0;  /* Default return condition */
        if (addr < sizeof(struct user_regs_struct))
            tmp = getreg(child, addr);
        else if (addr >= offsetof(struct user, u_debugreg[0]) &&
             addr <= offsetof(struct user, u_debugreg[7])) {
            addr -= offsetof(struct user, u_debugreg[0]);
            tmp = ptrace_get_debugreg(child, addr / sizeof(data));
        }
        ret = put_user(tmp, datap);
        break;
    }

我知道里面i387不支持阅读。我知道我可以通过调用来读取这些寄存器PTRACE_GETFPREGS。我的问题是:是否有特定原因导致禁用使用PTRACE_PEEKUSER和写入这些寄存器?PTRACE_POKEUSER

我的猜测是因为大多数字段都user_fpregs_struct小于64位,因此读写可能会覆盖多个寄存器。但是,我正在编写一个公开的资源,并将对此进行注释,所以我宁愿确定我的猜测是正确的。

答案1

只是猜测:您想读取数学协处理器寄存器。你检查过内核中i387的成员何时更新吗?struct user我没有,而且我可能是错的,但我的猜测并不常见,但在诸如核心转储之类的情况下。

来自 arch/x86/include/asm/user_64.h

struct user {
/* We start with the registers, to mimic the way that "memory" is returned
   from the ptrace(3,...) function.  */
  struct user_regs_struct regs; /* Where the registers are actually stored */
/* ptrace does not yet supply these.  Someday.... */
  int u_fpvalid;        /* True if math co-processor being used. */
                /* for this mess. Not yet used. */
  int pad0;
  struct user_i387_struct i387; /* Math Co-processor registers. */
  :
  unsigned long u_debugreg[8];
  :
};

因此,读取数学协处理器寄存器最好通过从 FPU 读取来完成。如果您检查内核如何执行PTRACE_GETFPREGS,您会发现它是从 FPU 而不是成员获取的struct user i387。使用 编写数学协处理器寄存器也是如此PTRACE_SETFPREGS

arch_ptrace

case PTRACE_GETFPREGS:  /* Get the child FPU state. */
    return copy_regset_to_user(child,
                   task_user_regset_view(current),
                   REGSET_FP,
                   0, sizeof(struct user_i387_struct),
                   datap);

task_user_regset_viewx86_64_regsets用于读取的返回值xfpregs_get

static struct user_regset x86_64_regsets[] __ro_after_init = {

    [REGSET_FP] = {
        .core_note_type = NT_PRFPREG,
        .n = sizeof(struct user_i387_struct) / sizeof(long),
        .size = sizeof(long), .align = sizeof(long),
        .active = regset_xregset_fpregs_active, .regset_get = xfpregs_get, .set = xfpregs_set
    },

}

const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{
    :
#ifdef CONFIG_X86_64
    return &user_x86_64_view;
#endif
}

相关内容