Why am I receiving SIGSEGV when invoking the sys_pause syscall?

…衆ロ難τιáo~ 提交于 2019-12-04 13:43:19

There were two corrections that needed to be made before the application worked correctly.


sa_restorer

Jester pointed me to this answer which mentioned that the kernel requires the sa_restorer member of sigaction to be filled in.

Fixing this required defining SA_RESTORER:

%define SA_RESTORER 0x04000000

...and initializing the sa_restorer and sa_flags members:

mov [act + sigaction.sa_flags], dword SA_RESTORER
lea rax, [restorer]
mov [act + sigaction.sa_restorer], rax

I then added an empty stub for the restorer function:

restorer:

    ret

At this point, the handler was invoked without error but the application was still crashing...


sys_rt_sigreturn

Apparently, the sa_restorer function needs to invoke the sys_rt_sigreturn syscall. This required defining sys_rt_sigreturn:

%define sys_rt_sigreturn 0x0f

The restorer function was then modified:

restorer:

    ; return from the signal handler
    mov rax, sys_rt_sigreturn
    syscall

At this point, the application ran without crashing.

Here's the entire working and corrected program by Nathan Osman. Answering here because such an example doesn't seem to exist anywhere else on the internet.

%define sys_write        0x01
%define sys_rt_sigaction 0x0d
%define sys_pause        0x22
%define sys_exit         0x3c
%define sys_rt_sigreturn 0x0f
%define SIGTERM 0x0f
%define SIGINT 0x02
%define STDOUT 0x01
%define SA_RESTORER 0x04000000

; Definition of sigaction struct for sys_rt_sigaction
struc sigaction
    .sa_handler  resq 1
    .sa_flags    resq 1
    .sa_restorer resq 1
    .sa_mask     resq 1
endstruc

section .data
    ; Message shown when a syscall fails
    error_msg     db  'syscall error', 0x0a
    error_msg_len equ $ - error_msg
    ; Message shown when SIGTERM is received
    sigterm_msg     db  'SIGTERM received', 0x0a
    sigterm_msg_len equ $ - sigterm_msg

section .bss
    act resb sigaction_size
    val resd 1

section .text
global _start
_start:
    ; Initialize act
    mov qword [act + sigaction.sa_handler], handler
    mov [act + sigaction.sa_flags], dword SA_RESTORER
    mov qword [act + sigaction.sa_restorer], restorer

    ; Set the handler
    mov rax, sys_rt_sigaction
    ;mov rdi, SIGINT
    mov rdi, SIGTERM
    lea rsi, [act]
    mov rdx, 0x00
    mov r10, 0x08
    syscall

    ; Ensure the syscall succeeded
    cmp rax, 0
    jne error

    ; Pause until a signal is received
    mov rax, sys_pause
    syscall

    ; Upon success, jump to exit
    jmp exit

error:
    ; Display an error message
    mov rax, sys_write
    mov rdi, STDOUT
    mov rsi, error_msg
    mov rdx, error_msg_len
    syscall

    ; Set the return value to one
    mov dword [val], 0x01

exit:
    ; Terminate the application gracefully
    mov rax, sys_exit
    mov rdi, [val]
    syscall

handler:
    ; Display a message
    mov rax, sys_write
    mov rdi, STDOUT
    mov rsi, sigterm_msg
    mov rdx, sigterm_msg_len
    syscall
    ret

restorer:
    ; return from the signal handler
    mov rax, sys_rt_sigreturn
    syscall

For easier testing, you can replace SIGTERM with SIGINT by uncommenting the first list here and commenting the second.

    ;mov rdi, SIGINT
    mov rdi, SIGTERM

Save it to signal.asm and compile and run with

nasm -f elf64 signal.asm -o signal.o && ld signal.o && ./a.out

In the SIGINT version, pressing Control-C to interrupt the program should print message 'SIGTERM received' (its also possible to change that to make it more accurate). In the SIGTERM version, instead run it in gdb

$ gdb ./a.out
[GNU gdb...]
(gdb) r
Starting program: /path/a.out 

And now press Control-C

^C
Program received signal SIGINT, Interrupt.
0x0000000000400107 in _start ()
(gdb) signal SIGTERM
Continuing with signal SIGTERM.
SIGTERM received
[Inferior 1 (process 22742) exited normally]
(gdb)

The 'SIGTERM received' message is printed as expected.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!