使用非规范地址检索内存数据会导致 SIGSEGV 而不是 SIGBUS
Retrieving memory data with non-canonical-address causes SIGSEGV rather than SIGBUS
我无法使用以下汇编代码生成“总线错误”。这里我使用的内存地址不是合法的“规范地址”。那么,我该如何触发该错误?
我在 Ubuntu 20.04 LTS 和 NASM 2.14.02 下 运行 这段代码,但它导致负载上出现 SIGSEGV 分段错误,而不是 SIGBUS。
global _start
section .text
_start:
mov rax, [qword 0x11223344557788]
mov rax, 60
xor rdi, rdi
syscall
编译后对应的X86-64汇编代码:
Disassembly of section .text:
0000000000401000 <_start>:
401000: 48 a1 88 77 55 44 33 movabs 0x11223344557788,%rax
401007: 22 11 00
40100a: b8 3c 00 00 00 mov [=11=]x3c,%eax
40100f: 48 31 ff xor %rdi,%rdi
401012: 0f 05 syscall
如果您查看 MOV 指令的指令集架构手册,您会发现访问 non-canonical 地址会产生 #GP(0)
一般保护错误:
Linux 将所有 #GP
异常映射到 SIGSEGV 信号(分段错误)。但是,在 Linux 中,有一种方法可以让 non-canonical 地址导致 总线错误 ,那就是让处理器引发 #SS
(堆栈段)异常。 Linux 将 #SS
异常映射到 SIGBUS 信号。将堆栈指针设置为non-canonical地址,然后执行堆栈相关操作会产生这样的异常。
此代码应产生 总线错误:
global _start
section .text
_start:
mov rsp, 0x8000000000000000 ; Set RSP to a non-canonical address
push rax ; Pushing value on stack should produce BUS ERROR
另一种在 Linux 上产生总线错误的方法是引发 #AC
(对齐检查)异常。如果您编写环 3(用户)代码启用 RFLAGS 中的对齐检查位(第 18 位)并执行未对齐的内存访问,您还应该收到 SIGBUS 信号。此代码应产生 总线错误 :
global _start
section .text
_start:
pushf ; Put current RFLAGS on the stack
or dword [rsp], 1<<18 ; Enable bit 18 (Alignment Check) of the
; RFLAGS value saved on stack
popf ; Pop new RFLAGS flags value into the RFLAGS register
mov eax, [rsp + 1] ; Move a DWORD value from unaligned address
; Should produce a BUS ERROR
我无法使用以下汇编代码生成“总线错误”。这里我使用的内存地址不是合法的“规范地址”。那么,我该如何触发该错误?
我在 Ubuntu 20.04 LTS 和 NASM 2.14.02 下 运行 这段代码,但它导致负载上出现 SIGSEGV 分段错误,而不是 SIGBUS。
global _start
section .text
_start:
mov rax, [qword 0x11223344557788]
mov rax, 60
xor rdi, rdi
syscall
编译后对应的X86-64汇编代码:
Disassembly of section .text:
0000000000401000 <_start>:
401000: 48 a1 88 77 55 44 33 movabs 0x11223344557788,%rax
401007: 22 11 00
40100a: b8 3c 00 00 00 mov [=11=]x3c,%eax
40100f: 48 31 ff xor %rdi,%rdi
401012: 0f 05 syscall
如果您查看 MOV 指令的指令集架构手册,您会发现访问 non-canonical 地址会产生 #GP(0)
一般保护错误:
Linux 将所有 #GP
异常映射到 SIGSEGV 信号(分段错误)。但是,在 Linux 中,有一种方法可以让 non-canonical 地址导致 总线错误 ,那就是让处理器引发 #SS
(堆栈段)异常。 Linux 将 #SS
异常映射到 SIGBUS 信号。将堆栈指针设置为non-canonical地址,然后执行堆栈相关操作会产生这样的异常。
此代码应产生 总线错误:
global _start
section .text
_start:
mov rsp, 0x8000000000000000 ; Set RSP to a non-canonical address
push rax ; Pushing value on stack should produce BUS ERROR
另一种在 Linux 上产生总线错误的方法是引发 #AC
(对齐检查)异常。如果您编写环 3(用户)代码启用 RFLAGS 中的对齐检查位(第 18 位)并执行未对齐的内存访问,您还应该收到 SIGBUS 信号。此代码应产生 总线错误 :
global _start
section .text
_start:
pushf ; Put current RFLAGS on the stack
or dword [rsp], 1<<18 ; Enable bit 18 (Alignment Check) of the
; RFLAGS value saved on stack
popf ; Pop new RFLAGS flags value into the RFLAGS register
mov eax, [rsp + 1] ; Move a DWORD value from unaligned address
; Should produce a BUS ERROR