linux – 为什么segfault而不是特权指令错误?
我试图在用户模式下执行特权指令rdmsr,我希望得到某种特权错误,但我得到一个段错误.我已经检查了asm,我正在将0x186加载到ecx中,这应该是PERFEVTSEL0,基于 manual,第1171页. segfault的原因是什么,如何修改下面的代码来修复它? 我想在破解内核模块之前解决这个问题,因为我不希望这个段错误炸毁我的内核. 更新:我在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("%lun",read_msr(c)); return 0; } 解决方法我将尝试回答的问题:为什么上面的代码导致SIGSEGV而不是SIGILL,虽然代码没有内存错误,但是非法指令(从非特权用户速度调用的特权指令)?我希望得到一个带有si_code ILL_PRVOPC而不是段错误的SIGILL.你的问题目前是3岁,今天我偶然发现了同样的行为.我也很失望:-(
原因似乎是Linux内核代码决定发送SIGSEGV.这是负责任的职能: 在your follow up question中,您获得了其他汇编指令的列表,这些汇编指令作为SIGSEGV传播到用户空间,尽管它们实际上是一般性保护错误.我找到了你的问题,因为我用cli触发了这个行为.
从Linux内核4.9开始,我不知道有任何可靠的方法可以区分内存错误(我希望是SIGSEGV)和来自用户空间的特权指令错误. 可能有非常黑客和不可移植的方式来解决这些案件.当特权指令导致SIGSEGV时,siginfo_t si_code被设置为一个值,该值不直接列在man 2 sigaction的SIGSEGV部分中.记录的值是SEGV_MAPERR,SEGV_ACCERR,SEGV_PKUERR,但我的系统上得到了SI_KERNEL(0x80).根据手册页,SI_KERNEL是一个代码“可以放在任何信号的si_code中”.在strace中,您会看到SIGSEGV {si_signo = SIGSEGV,si_code = SI_KERNEL,si_addr = 0}.负责的内核代码是here. 也可以为this字符串grep dmesg. 请永远不要使用这两种方法来区分生产系统上的GPF和内存错误. 代码的特定解决方案:只是不要从用户空间运行rdmsr.但是,如果您正在寻找一种通用的方法来弄清楚程序收到SIGSEGV的原因,那么这个答案实在令人不满意. (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |