【问题标题】:Why a segfault instead of privilege instruction error?为什么是段错误而不是特权指令错误?
【发布时间】:2014-03-10 05:05:34
【问题描述】:

我试图在用户模式下执行特权指令rdmsr,我希望得到某种特权错误,但我得到了一个段错误。我检查了asm,我正在将0x186 加载到ecx,它应该是PERFEVTSEL0,基于manual,第1171 页。

段错误的原因是什么,如何修改下面的代码来修复它?

我想在破解内核模块之前解决这个问题,因为我不希望这个段错误炸毁我的内核。

更新:我正在运行 Intel(R) Xeon(R) CPU X3470

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>

#include <sched.h>
#include <assert.h>

uint64_t
read_msr(int ecx)
{
    unsigned int a, d;
    __asm __volatile("rdmsr" : "=a"(a), "=d"(d) : "c"(ecx));
    return ((uint64_t)a) | (((uint64_t)d) << 32);
}

int main(int ac, char **av)
{
    uint64_t start, end;
    cpu_set_t cpuset;
    unsigned int c = 0x186;
    int i = 0;

    CPU_ZERO(&cpuset);
        CPU_SET(i, &cpuset);
        assert(sched_setaffinity(0, sizeof(cpuset), &cpuset) == 0);

    printf("%lu\n", read_msr(c));
    return 0;
}

【问题讨论】:

  • 查看dmesg输出,我想你会看到traps,这表明你正在尝试从用户模式执行特权指令。
  • @rakib,dmesg 的输出:general protection ip:4005d0 sp:7fff6dea4070 error:0。我想这就是我需要知道的。我会接受这个答案,并单独提出后续问题。
  • 真的需要在单独的问题中提出这个问题吗?你得到了你想要的。
  • 我对此感到好奇,因为当我深入研究asm 时,我想更普遍地了解哪些事情会导致假segfaults

标签: linux performance assembly x86


【解决方案1】:

我将尝试回答的问题:为什么上面的代码导致SIGSEGV而不是SIGILL,虽然代码没有内存错误,但是一个非法指令(从非特权用户调用的特权指令) ?


我希望得到一个 SIGILLsi_code ILL_PRVOPC 而不是段错误。你的问题目前是 3 岁,今天,我偶然发现了同样的行为。我也很失望:-(


段错误的原因是什么

原因似乎是Linux内核代码决定发送SIGSEGV。这是负责的功能: http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/kernel/traps.c#L487 看看函数的最后一行。

your follow up question 中,您有一个其他汇编指令列表,这些指令作为SIGSEGV 传播到用户空间,尽管它们实际上是一般保护错误。我找到了你的问题,因为我触发了 cli 的行为。

我该如何修改下面的代码来修复它?

从 Linux 内核 4.9 开始,我不知道有任何可靠的方法来区分内存错误(我希望是 SIGSEGV)和来自用户空间的特权指令错误.

可能有一种非常笨拙且不可移植的方式来区分这些案例。当特权指令导致SIGSEGV 时,siginfo_t si_code 被设置为未直接列在man 2 sigactionSIGSEGV 部分中的值。记录的值为SEGV_MAPERRSEGV_ACCERRSEGV_PKUERR,但我在我的系统上得到SI_KERNEL (0x80)。根据手册页,SI_KERNEL 是一个代码“可以放在任何信号的 si_code 中”。在 strace 中,您会看到 SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0}。负责的内核代码是here

也可以使用 grep dmesg 获取 this 字符串。

请永远不要使用这两种方法来区分生产系统上的 GPF 和内存错误。

针对您的代码的特定解决方案:只是不要从用户空间运行rdmsr。但是,如果您正在寻找一种通用方法来找出程序收到SIGSEGV 的原因,那么这个答案确实令人不满意。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-10
    • 2014-01-20
    • 2014-05-23
    • 1970-01-01
    • 2018-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多