Различия в стеке между обработчиком сигнала, вызываемым напрямую и с помощью повышения ()?

Я пытаюсь изменить адрес возврата в стеке в обработчике ошибок сегмента, чтобы он пропускал инструкцию по ошибке. Однако я получаю ошибку сегмента всякий раз, когда пытаюсь изменить адрес возврата, если я не вызываю обработчик сигнала напрямую.

gdb не подходит для отладки, когда программа делает segfault, но когда я делаю info frame, я вижу, что после segfault есть «уровень кадра 2», а не «уровень кадра 0»? Я не знаю, откуда GDB получает эту информацию, потому что, когда я пытаюсь ввести x/12xw $ebp или сколько угодно слов, я не вижу обратного адреса для main()...

Скомпилировано с -m32 -z execstack -fno-stack-protector в CentOS linux

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

void segment_fault_handler(int signum)
{
    char* ret = (char*)(&signum)-4;
    *(ret) += 8;
}

int main()
{
    int phail = 0;

    signal(SIGSEGV, segment_fault_handler);

    segment_fault_handler(7); //Only by using this can I skip the next instruction

    phail = *( (int *) 0);

    printf("Win!\n");

    return 0;
} 

Причина, по которой я увеличиваю на 8, заключается в том, что инструкция phail в main() составляет 8 байтов:

0x080484e2 <+37>:   movl   $0x7,(%esp)
0x080484e9 <+44>:   call   0x8048480 <segment_fault_handler>
0x080484ee <+49>:   mov    $0x0,%eax
0x080484f3 <+54>:   mov    (%eax),%eax
0x080484f5 <+56>:   mov    %eax,0x1c(%esp)
0x080484f9 <+60>:   movl   $0x80485b4,(%esp)
0x08048500 <+67>:   call   0x8048350 <puts@plt>

Нужно ли немного увеличить смещение? Нужно ли менять мой метод доступа к стеку (который, как мне кажется, соответствует EBP+4) при работе с ситуацией отказа сегмента?


person Dorj    schedule 27.01.2017    source источник
comment
Вам нужно изменить сохраненный ПК в структуре ucontext_t, переданной обработчику, не непосредственный адрес возврата функции обработки сигнала. (И не вызывайте его напрямую.) Пример программы по адресу stackoverflow.com/questions/5119288/ показывает, как получить доступ к структуре ucontext_t.   -  person zwol    schedule 28.01.2017


Ответы (1)


Зарегистрируйте обработчик сигнала с помощью sigaction, а не signal, и используйте флаг SA_SIGINFO, чтобы получить siginfo_t, описывающий причину сигнала. Это позволит вам обрабатывать SIGSEGV, вызванное сбоем, иначе, чем явный raised или отправленный kill, sigqueue и т. д. Это также дает вам ucontext_t, необходимое для проверки состояния во время сбоя и, при необходимости, изменения его перед возвратом.

Кстати, вообще signal в любом случае - плохая идея, потому что не указано, установлен ли флаг SA_RESTART - и вы почти всегда хотите SA_RESTART. Заведите привычку использовать sigaction и относиться к signal как к устаревшему.

person R.. GitHub STOP HELPING ICE    schedule 27.01.2017