asm 中的信号处理:为什么在调用 sys_pause 系统调用时会收到 SIGSEGV? [英] Signal handling in asm: Why am I receiving SIGSEGV when invoking the sys_pause syscall?

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

问题描述

我正在尝试创建一个 x86_64 汇编程序,该程序在发送 SIGTERM 信号时显示收到 SIGTERM".我的应用程序直接使用 Linux 系统调用:

%define sys_write 0x01%define sys_rt_sigaction 0x0d%define sys_pause 0x22%define sys_exit 0x3c%define SIGTERM 0x0f%定义标准输出0x01;sys_rt_sigaction sigaction 结构的定义结构信号.sa_handler resq 1.sa_flags resq 1.sa_restorer resq 1.sa_mask resq 1端部结构.data 节;系统调用失败时显示的消息error_msg db '系统调用错误',0x0aerror_msg_len equ $ - error_msg;收到 SIGTERM 时显示的消息sigterm_msg db '收到 SIGTERM', 0x0asigterm_msg_len equ $ - sigterm_msg.bss 节行动 resb sigaction_sizeval resd 1节.text全局_start_开始:;初始化行为lea rax, [处理程序]mov [act + sigaction.sa_handler], rax;设置处理程序mov rax, sys_rt_sigactionmov rdi, SIGTERMle rsi, [法案]移动 rdx, 0x00移动 r10, 0x08系统调用;确保系统调用成功cmp rax, 0错误;暂停直到收到信号mov rax, sys_pause系统调用;成功后跳转退出退出错误:;显示错误信息mov rax, sys_writemov rdi, 标准输出mov rsi, error_msgmov rdx, error_msg_len系统调用;将返回值设置为 1mov 双字 [val], 0x01出口:;优雅地终止应用程序mov rax, sys_exitmov rdi, [val]系统调用处理程序:;显示消息mov rax, sys_writemov rdi, 标准输出mov rsi, sigterm_msgmov rdx, sigterm_msg_len系统调用回复

当我运行应用程序时,它在 sys_pause 系统调用处挂起(如预期),但当我发送 SIGTERM 信号时,它因分段错误而崩溃.>

所以我将应用程序加载到 GDB 中以找出发生了什么:

(gdb) break _start断点 1 在 0x4000b0(gdb) 运行启动程序:[...]断点 1, 0x00000000004000b0 in _start()(gdb) 信息过程处理 9639(gdb) 继续继续.

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

程序接收信号SIGTERM,终止.0x00000000004000ec 在 _start ()

然后我跑了:

(gdb) disas _start函数 _start 的汇编代码转储:0x00000000004000b0 <+0>: lea 0x400123,%rax0x00000000004000b8 <+8>: mov %rax,0x6001600x00000000004000c0 <+16>: mov $0xd,%eax0x00000000004000c5 <+21>: mov $0xf,%edi0x00000000004000ca <+26>: lea 0x600160,%rsi0x00000000004000d2 <+34>: mov $0x0,%edx0x00000000004000d7 <+39>: mov $0x8,%r10d0x00000000004000dd <+45>:系统调用0x00000000004000df <+47>: cmp $0x0,%rax0x00000000004000e3 <+51>: jne 0x4000ee <error>0x00000000004000e5 <+53>: mov $0x22,%eax0x00000000004000ea <+58>:系统调用=>0x00000000004000ec <+60>: jmp 0x400114 <exit>汇编程序转储结束.

然后我继续申请:

(gdb) 继续继续.程序收到信号 SIGSEGV,分段错误.0x00000000004000ec 在 _start ()

信号处理程序从未被调用,应用程序崩溃了.

我做错了什么?

解决方案

在应用程序正常工作之前,需要进行两项更正.

<小时>

sa_restorer

Jester 向我指出了 this answer 其中提到内核需要填写sigactionsa_restorer 成员.

修复这个需要定义SA_RESTORER:

%define SA_RESTORER 0x04000000

...并初始化 sa_restorersa_flags 成员:

mov [act + sigaction.sa_flags], 双字 SA_RESTORERlea rax,[恢复者]mov [act + sigaction.sa_restorer], rax

然后我为 restorer 函数添加了一个空存根:

恢复器:回复

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

<小时>

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.

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

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