为什么在调用sys_pause系统调用时收到SIGSEGV? [英] Why am I receiving SIGSEGV when invoking the sys_pause syscall?
问题描述
我试图创建一个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屋!