为什么在调用sys_pause系统调用时收到SIGSEGV? [英] Why am I receiving SIGSEGV when invoking the sys_pause syscall?

查看:354
本文介绍了为什么在调用sys_pause系统调用时收到SIGSEGV?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图创建一个x86_64汇编程序,在发送 SIGTERM 信号时显示SIGTERM received。我的应用程序直接使用Linux系统调用:

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

%SIGTERM 0x0f

%define STDOUT 0x01


; sigaction结构体定义为sys_rt_sigaction
结构体信号
.sa_handler resq 1
.sa_flags resq 1
.sa_restorer resq 1
.sa_mask resq 1
endstruc


部分.data

;系统调用失败时显示消息
error_msg db'系统调用错误',0x0a
error_msg_len equ $ - error_msg

;收到SIGTERM时显示的消息
sigterm_msg db'SIGTERM received',0x0a
sigterm_msg_len equ $ - sigterm_msg


部分.bss

act resb sigaction_size
val resd 1


section .text
global _start

_start:

;初始化act
lea rax,[handler]
mov [act + sigaction.sa_handler],rax

;设置处理程序
mov rax,sys_rt_sigaction
mov rdi,SIGTERM
ri rsi,[act]
mov rdx,0x00
mov r10,0x08
syscall

;确保系统调用成功
cmp rax,0
jne error

;暂停直到收到信号
mov rax,sys_pause
系统调用

;成功后,跳至退出
jmp退出

错误:

;显示错误消息
mov rax,sys_write
mov rdi,STDOUT
mov rsi,error_msg
mov rdx,error_msg_len
系统调用

;将返回值设置为一个
mov dword [val],0x01

exit:

;优雅地终止应用程序
mov rax,sys_exit
mov rdi,[val]
系统调用

处理程序:

;显示消息
mov rax,sys_write
mov rdi,STDOUT
mov rsi,sigterm_msg
mov rdx,sigterm_msg_len
系统调用

ret

运行应用程序时,它会挂起(如预期的那样)在 sys_pause 系统调用,但当我发送 SIGTERM 信号时,它会崩溃并出现分段错误。



因此,我将应用程序加载到GDB中以了解发生了什么:

 (gdb)break _start 
断点1 at 0x4000b0
(gdb)运行
启动程序:[...]

_start()中的断点1,0x00000000004000b0
(gdb)info proc
进程9639
(gdb)继续
继续。

GDB会话挂起,然后我打开另一个终端并运行 kill SIGTERM 9639 。这导致了以下输出:

 编程接收到的信号SIGTERM,已终止。 
0x00000000004000ec in _start()

然后我跑了:

 (gdb)disas _start 
函数_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>:系统调用
0x00000000004000df <+ 47>:cmp $ 0x0,%rax
0x00000000004000e3 <+ 51>:jne 0x4000ee< error>
0x00000000004000e5< + 53> ;: mov $ 0x22,%eax
0x00000000004000ea< + 58> ;:系统调用
=> 0x00000000004000ec< + 60>:jmp 0x400114< exit>
汇编器转储结束。

然后我继续申请:

 (gdb)继续
继续。

编程接收到的信号SIGSEGV,分段故障。
0x00000000004000ec in _start()

信号处理程序从不调用,应用程序崩溃。



我做错了什么?

解决方案

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






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 

然后修改 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.

这篇关于为什么在调用sys_pause系统调用时收到SIGSEGV?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆