且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

为什么在调用sys_pause系统调用时收到SIGSEGV?

更新时间:2023-10-29 23:26:16

需要在应用程序正常工作之前完成。






sa_restorer



杰斯特指出我这个答案,它提到内核需要填入 sigaction sa_restorer 成员。



解决此问题需要定义 SA_RESTORER

 %define SA_RESTORER 0x04000000 

...并初始化 sa_restorer sa_flags 成员:

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

然后我为恢复器函数添加一个空存根:

 恢复器:

ret

此时,处理程序被调用时没有错误,但应用程序是仍然崩溃... ...



sys_rt_sigreturn



显然, sa_restorer 函数需要调用 sys_rt_sigreturn 系统调用。这需要定义 sys_rt_sigreturn

 %define sys_rt_sigreturn 0x0f 
$ c>

然后修改 restorer 函数:

 恢复者:

;从信号处理程序返回
mov rax,sys_rt_sigreturn
系统调用






此时,应用程序不会崩溃。


I am trying to create an x86_64 assembly program that displays "SIGTERM received" whenever the SIGTERM signal is sent. My application is using Linux syscalls directly:

%define sys_write        0x01
%define sys_rt_sigaction 0x0d
%define sys_pause        0x22
%define sys_exit         0x3c

%define SIGTERM 0x0f

%define STDOUT 0x01


; 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
    lea rax, [handler]
    mov [act + sigaction.sa_handler], rax

    ; Set the handler
    mov rax, sys_rt_sigaction
    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

When I run the application, it hangs (as expected) at the sys_pause syscall but when I send the SIGTERM signal, it crashes with a segmentation fault.

So I loaded the application into GDB to figure out what was happening:

(gdb) break _start
Breakpoint 1 at 0x4000b0
(gdb) run
Starting program: [...] 

Breakpoint 1, 0x00000000004000b0 in _start ()
(gdb) info proc
process 9639
(gdb) continue
Continuing.

The GDB session hung and I then opened another terminal and ran kill SIGTERM 9639. This resulted in the following output:

Program received signal SIGTERM, Terminated.
0x00000000004000ec in _start ()

I then ran:

(gdb) disas _start
Dump of assembler code for function _start:
   0x00000000004000b0 <+0>:     lea    0x400123,%rax
   0x00000000004000b8 <+8>:     mov    %rax,0x600160
   0x00000000004000c0 <+16>:    mov    $0xd,%eax
   0x00000000004000c5 <+21>:    mov    $0xf,%edi
   0x00000000004000ca <+26>:    lea    0x600160,%rsi
   0x00000000004000d2 <+34>:    mov    $0x0,%edx
   0x00000000004000d7 <+39>:    mov    $0x8,%r10d
   0x00000000004000dd <+45>:    syscall 
   0x00000000004000df <+47>:    cmp    $0x0,%rax
   0x00000000004000e3 <+51>:    jne    0x4000ee <error>
   0x00000000004000e5 <+53>:    mov    $0x22,%eax
   0x00000000004000ea <+58>:    syscall 
=> 0x00000000004000ec <+60>:    jmp    0x400114 <exit>
End of assembler dump.

Then I continued the application:

(gdb) continue
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x00000000004000ec in _start ()

The signal handler is never invoked and the application has crashed.

What am I doing wrong?

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.