Retrieving memory data with non-canonical-address causes SIGSEGV rather than SIGBUS
Asked Answered
I

1

2

I can not produce a "Bus error" with the following assembly code. Here the memory address I use is not a legal "canonical-address". So, how can I trigger that error?

I was running this snippet of code under Ubuntu 20.04 LTS with NASM 2.14.02, but it results in a SIGSEGV segmentation fault on the load, not SIGBUS.

global _start
section .text
_start:
    mov rax, [qword 0x11223344557788]
    mov rax, 60
    xor rdi, rdi
    syscall

Corresponding X86-64 assembly code after compiling:

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    $0x3c,%eax
  40100f:   48 31 ff                xor    %rdi,%rdi
  401012:   0f 05                   syscall
Inconstant answered 28/6, 2020 at 11:8 Comment(8)
You're running this under Linux, right? Please tag if so.Stiffler
Have you tried using the kill system call to deliver a SIGBUS to yourself?Dromedary
It seems that Linux chooses to deliver SIGSEGV for a non-canonical address. You can get SIGBUS by reading from a mmaped page if the underlying file has been truncated, and you can of course use asm to make the system call to make that happen. Or of course raise(SIGBUS). I think there is some kind of x86 exception (other than that special case of #PF) that the OS handles by delivering SIGBUS; possibly alignment-checking #AC, if you had a kernel module enable the AC flag?Stiffler
If you're looking for a HW-exception specific way, please make your title and/or question body more specific / explicit about that. Otherwise as @Dromedary points out, kill(getpid(), SIGBUS) or tgkill is a trivial answer.Stiffler
@fuz: nope, I just want to see how the OS reacts to this kind of data retrieving operation with a non-canonical-address.Inconstant
That's a different question. I had kind of expected SIGBUS for a non-canonical address, that would be logical, but the SIGSEGV we actually get also makes logical sense. You don't have that memory mapped. The fact that you couldn't map that address might mean you'd get -EINVAL from mmap if you tried with MAP_FIXED.Stiffler
By the way, the address you are using is canonical on Ice Lake CPUs.Linn
@Kit.: Only if you enabled PML5, though, right? Or would it #PF instead of #GP even if the kernel hadn't enabled that bit?Stiffler
S
7

If you review the Instruction Set Architecture manual for the MOV instruction you would find that accessing a non-canonical address yields a #GP(0) General Protection Fault:

enter image description here

Linux maps all #GP exceptions to SIGSEGV signal (Segmentation Fault). However, in Linux there is a way for a non-canonical address to cause a Bus Error and that is by getting the processor to raise an #SS (Stack Segment) exception. Linux maps #SS exceptions to the SIGBUS signal. Setting the stack pointer to a non-canonical address and then performing a stack related operation will produce such an exception.

This code should produce a Bus Error:

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

One other way of producing a Bus Error on Linux is to raise an #AC (Alignment Check) exception. If you write ring 3 (user) code that enables the Alignment Check bit (bit 18) in RFLAGS and do an unaligned memory access you should also receive a SIGBUS signal. This code should produce a Bus Error:

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
Sharecrop answered 28/6, 2020 at 12:49 Comment(2)
@Joseph, although your edit works mine does as well.With the AC bit enabled all memory accesses are checked whether on a stack operation or not.Sharecrop
Indeed. I just wanted to make it more obvious that the signal is from the misalignment and not from trying to read an unmapped page.Contend

© 2022 - 2024 — McMap. All rights reserved.