其他分享
首页 > 其他分享> > 我可以排除SIGBUS是由“次要页面错误”引发的吗? (内核日志没有分配失败)

我可以排除SIGBUS是由“次要页面错误”引发的吗? (内核日志没有分配失败)

作者:互联网

动机

我试图提高我对SIGBUS error in Xwayland的理解.自2018年2月20日左右以来,一些Fedora Linux用户已经看到了这种情况,其中包括Xwayland 1.19.6-5.fc27.x86_64和Linux内核4.15.3-300.fc27. X86-64.

可悲的是,我没有kernel “segfault” log message(或等同于SIGBUS). Xwayland有一些无意义的代码可以捕获致命的信号.但我可以通过调试coredump看到siginfo,这似乎差不多好.

定义

据我所知,当一页虚拟内存在RAM中不可用时,会发生“主要页面错误”,必须从磁盘读取.对于这个问题,我认为我对ext4文件系统支持的页面特别感兴趣(例如,没有直接访问块设备).

因此,“次要页面错误”是指不需要磁盘访问.我假设差异相当明确,因为Linux公开了主要和次要页面错误的计数器.

我的问题

如果内核发送一个程序SIGBUS,我想知道我是否应该普遍认为这将是一个主要的页面错误.

根据coredump和disassembly,程序在接收SIGBUS时读取内存,而不是写入内存. siginfo-> si_addr中的故障地址在映射的系统可执行文件中,用户无法写入,并且地址似乎在当前文件长度的范围内.实际上在调试coredump时,我已经从内存地址读取了非常令人信服的值.似乎coredump生成过程没有困难阅读这个地址:-(.

我也有信心排除“无效地址对齐”情况(BUS_ADRALN),因为siginfo-> si_code是2,即BUS_ADRERR,“不存在的物理地址”.另外,因为我在x86上,在大多数情况下允许未对齐访问,并且陷阱不在任何SSE扩展指令中.

我考虑了内核通常负责的内容,当它处理它确定为“次要”的页面错误时.我认为小故障可能无法分配内存,从而引发SIGBUS.但是,我相信我会注意到这样的分配失败:

我有足够的免费交换来驱逐用户页面,我没有注意到当我的系统开始交换时通常会出现明显的减速.在将笔记本电脑从暂停状态唤醒到ram之后几秒钟发生了崩溃,即使在~100MB / s时也不足以填满8GB的掉线.
我也没有看到内存日志中出现了恐惧内存(OOM)杀手,正如我所期望的,如果内核分配页面框架或页面表失败.

是否有其他可能导致次要页面错误失败并导致SIGBUS?即在内核日志中查找错误时,是否有一些我不会注意到的原因?哪个可以快速发作?

同样,多个coredump将此显示为通过从文件系统上的映射文件读取而触发的页面错误.

内心动机

我真的想错过一个小页面错误的案例.因为这可怕的另一面是我看不出这个SIGBUS是如何由硬页故障方面引起的.几个月前,我们几个用户的错误看起来非常相似.我的内核日志中没有IO错误.在正常操作期间,我在读取指示的文件时没有IO错误.运行rpm –verify –all时,或者在HDD上运行扩展SMART测试时,我没有错误.不幸的是,我似乎很少有嫌犯.我最接近的嫌疑是内核升级,我显然更愿意排除;日期并不完全证明,但并不完全排除.下一个最接近日期的是今年的微码更新;这似乎更难以确定.

轻微页面错误的已知原因

>从逻辑上讲,在为MAP_PRIVATE映射实现写时复制时,听起来就像是发生了次要的页面错误.
>它还应包括/ dev / zero或MAP_ANONYMOUS上的读取错误,假设内核确实将not实现为reading a shared zero page并且没有实现它们以立即为整个映射分配页面.
>但更一般地说,它可能是任何首次访问页面.这是因为看起来内存映射的页表通常是按需填充的. (这将由页面错误完成,如果文件页面已经在缓存中,那么它只是一个小的页面错误).

MAP_NONBLOCK (since Linux 2.5.46)

This flag is meaningful only in conjunction with MAP_POPULATE.
Don’t perform read-ahead: create page tables entries only for
pages that are already present in RAM. Since Linux 2.6.23, this
flag causes MAP_POPULATE to do nothing. One day, the combina‐
tion of MAP_POPULATE and MAP_NONBLOCK may be reimplemented.

编辑:进一步摘录详述上述内容

一位评论者要求提供更具体的细节,以澄清错误的地址和指示.初始链接https://bugzilla.redhat.com/show_bug.cgi?id=1557682中有许多摘录

故障因bug链接中的描述而异.以下是最近一个实例的新摘录.

$gdb 2018-03-21.core
...
Core was generated by `/usr/bin/Xwayland :0 -rootless -terminate -core -listen 4 -listen 5 -displayfd'.
Program terminated with signal SIGBUS, Bus error.
#0  _dl_fixup (l=0x7fc0be2e0130, reloc_arg=203) at ../elf/dl-runtime.c:73
73    const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
[Current thread is 1 (Thread 0x7fc0be29fa80 (LWP 1918))]
(gdb) p $_siginfo.si_signum
$1 = 7
(gdb) p $_siginfo.si_code
$2 = 2
(gdb) p $_siginfo._sifields._sigfault.si_addr
$3 = (void *) 0x41bd80
(gdb) disassemble
Dump of assembler code for function _dl_fixup:
   0x00007fc0be0c8bd0 <+0>: push   %rbx
   0x00007fc0be0c8bd1 <+1>: mov    %rdi,%r10
   0x00007fc0be0c8bd4 <+4>: mov    %esi,%esi
   0x00007fc0be0c8bd6 <+6>: lea    (%rsi,%rsi,2),%rdx
   0x00007fc0be0c8bda <+10>:    sub    $0x10,%rsp
   0x00007fc0be0c8bde <+14>:    mov    0x68(%rdi),%rax
   0x00007fc0be0c8be2 <+18>:    mov    0x8(%rax),%rdi
   0x00007fc0be0c8be6 <+22>:    mov    0xf8(%r10),%rax
   0x00007fc0be0c8bed <+29>:    mov    0x8(%rax),%rax
   0x00007fc0be0c8bf1 <+33>:    lea    (%rax,%rdx,8),%r8
   0x00007fc0be0c8bf5 <+37>:    mov    0x70(%r10),%rax
=> 0x00007fc0be0c8bf9 <+41>:    mov    0x8(%r8),%rcx
(gdb) p/x $r8
$4 = 0x41bd78
(gdb) p/x $r8 + 8
$5 = 0x41bd80

请注意,此指令根据突出显示的源代码行获取值reloc-> r_info.

(gdb) p reloc
$6 = (const Elf64_Rela * const) 0x41bd78
(gdb) p &reloc->r_info
$7 = (Elf64_Xword *) 0x41bd80
(gdb) p *reloc
$8 = {r_offset = 8443504, r_info = 936302870535, r_addend = 0}

错误地址属于下面的文本映射(来自abrtd捕获的地图文件):

00400000-0060b000 r-xp 00000000 fd:00 1708508                            /usr/bin/Xwayland
0080a000-0080d000 r--p 0020a000 fd:00 1708508                            /usr/bin/Xwayland
0080d000-00817000 rw-p 0020d000 fd:00 1708508                            /usr/bin/Xwayland

$size -x /usr/bin/Xwayland
   text    data     bss     dec     hex filename
0x209ffb     0xbe9d 0x1f3e0 2314872  235278 /usr/bin/Xwayland

解决方法:

我当然在内核中有一些错误,除非它是内核自我测试中的错误.

编辑:嗯,实际上似乎其他人也注意到最近GS自我测试失败,但它已经存在于较旧的内核中,并且也出现在AMD cpus上.目前似乎没有关于如何解决它的结论. https://lkml.org/lkml/2018/1/26/436

所以这不是它本身的错误,虽然我不能排除这个GS错误会在PTI启用或其他什么时导致更突出的破坏.

$uname -r
4.15.10-300.fc27.x86_64

$git describe --all
heads/4.15.10
$cat ./Documentation/x86/pti.txt
...
2. Run several copies of all of the tools/testing/selftests/x86/ tests
   (excluding MPX and protection_keys) in a loop on multiple CPUs for
   several minutes.  These tests frequently uncover corner cases in the
   kernel entry code.  In general, old kernels might cause these tests
   themselves to crash, but they should never crash the kernel.

$cd tools/testing/selftests/x86
$make
...

在4x终端中匹配我的4x硬件线程:

sh -c ' while true; do for i in *; do if test -x $i; then ./$i || exit; fi ; done; done '

失败很快出现:

[RUN]   ARCH_SET_GS(0x200000000), then schedule to 0x200000000
    Before schedule, set selector to 0x3
    other thread: ARCH_SET_GS(0x200000000) -- sel is 0x0
[FAIL]  GS/BASE changed from 0x3/0x0 to 0x0/0x0

[RUN]   Executing 6-argument 32-bit syscall via VDSO
[WARN]  Flags before=0000000000200ed7 id 0 00 o d i s z 0 a 0 p 1 c
[WARN]  Flags  after=0000000000200682 id 0 00 d i s 0 0 1 
[WARN]  Flags change=0000000000000855 0 00 o z 0 a 0 p 0 c
[OK]    Arguments are preserved across syscall
[NOTE]  R11 has changed:0000000000200682 - assuming clobbered by SYSRET insn
[OK]    R8..R15 did not leak kernel data
[RUN]   Executing 6-argument 32-bit syscall via INT 80
[OK]    Arguments are preserved across syscall
[OK]    R8..R15 did not leak kernel data
[RUN]   Running tests under ptrace
[RUN]   Executing 6-argument 32-bit syscall via VDSO
[WARN]  Flags before=0000000000200ed7 id 0 00 o d i s z 0 a 0 p 1 c
[WARN]  Flags  after=0000000000200686 id 0 00 d i s 0 0 p 1 
[WARN]  Flags change=0000000000000851 0 00 o z 0 a 0 0 c
[OK]    Arguments are preserved across syscall
[NOTE]  R11 has changed:0000000000200686 - assuming clobbered by SYSRET insn
[OK]    R8..R15 did not leak kernel data
[RUN]   Executing 6-argument 32-bit syscall via INT 80
[OK]    Arguments are preserved across syscall
[OK]    R8..R15 did not leak kernel data
Warning: failed to find getcpu in vDSO
[RUN]   Testing getcpu...
[OK]    CPU 0: syscall: cpu 0, node 0
[OK]    CPU 1: syscall: cpu 1, node 0
[OK]    CPU 2: syscall: cpu 2, node 0
[OK]    CPU 3: syscall: cpu 3, node 0
[RUN]   Testing getcpu...
[OK]    CPU 0: syscall: cpu 0, node 0 vdso: cpu 0, node 0 vsyscall: cpu 0, node 0
[OK]    CPU 1: syscall: cpu 1, node 0 vdso: cpu 1, node 0 vsyscall: cpu 1, node 0
[OK]    CPU 2: syscall: cpu 2, node 0 vdso: cpu 2, node 0 vsyscall: cpu 2, node 0
[OK]    CPU 3: syscall: cpu 3, node 0 vdso: cpu 3, node 0 vsyscall: cpu 3, node 0
[NOTE]  failed to find getcpu in vDSO
[RUN]   test gettimeofday()
    vDSO time offsets: 0.000006 0.000000
[OK]    vDSO gettimeofday()'s timeval was okay
[RUN]   test time()
[FAIL]  vDSO returned the wrong time (1522063297 1522063296 1522063297)

标签:c-3,linux,x86-64,sigbus
来源: https://codeday.me/bug/20190627/1304672.html