2013-07-16 11 views
5

używam sigaction obsłużyć wyjątek strona błędu, a funkcja obsługi jest defind tak:Jak zidentyfikować odczytu lub zapisu operacji od strony błędu podczas korzystania z obsługi sigaction na SIGSEGV (Linux)

void sigaction_handler(int signum, siginfo_t *info, void *_context) 

Więc to łatwo uzyskać adres błędu strony czytając info-> si_addr.

Pytanie jest, jak wiadomo, czy ta operacja jest pamięć READ lub NAPISZ?

znalazłem rodzaj _context parametru jest ucontext_t zdefiniowanym w/usr/include/sys/ucontext.h

Jest CR2 pole zdefiniowane w mcontext_t, ale unforunately, to jest tylko dostępna, gdy x86_64 nie jest zdefiniowany, więc nie mogłem użyć cr2 do identyfikacji operacji odczytu/zapisu.

Na anotherway, jest struktura o nazwie sigcontext zdefiniowane w/usr/to/bity/sigcontext.h Ta struktura zawiera CR2 dziedzinie. Ale nie wiem, skąd to wziąć.

Odpowiedz

6

Oto pokolenie SIGSEGV z jądra arch/x86/mm/fault.c, __bad_area_nosemaphore() funkcja: http://lxr.missinglinkelectronics.com/linux+v3.12/arch/x86/mm/fault.c#L760

760    tsk->thread.cr2   = address; 
761    tsk->thread.error_code = error_code; 
762    tsk->thread.trap_nr  = X86_TRAP_PF; 
763 
764    force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0); 

Jest error_code pole, a wartości są zdefiniowane w arch/x86/mm/fault.c też: http://lxr.missinglinkelectronics.com/linux+v3.12/arch/x86/mm/fault.c#L23

23/* 
    24 * Page fault error code bits: 
    25 * 
    26 * bit 0 == 0: no page found  1: protection fault 
    27 * bit 1 == 0: read access   1: write access 
    28 * bit 2 == 0: kernel-mode access 1: user-mode access 
    29 * bit 3 ==       1: use of reserved bit detected 
    30 * bit 4 ==       1: fault was an instruction fetch 
    31 */ 
    32enum x86_pf_error_code { 
    33 
    34  PF_PROT   =    1 << 0, 
    35  PF_WRITE  =    1 << 1, 
    36  PF_USER   =    1 << 2, 
    37  PF_RSVD   =    1 << 3, 
    38  PF_INSTR  =    1 << 4, 
    39}; 

Dokładne informacje o typie dostępu są przechowywane w thread_struct.error_code: http://lxr.missinglinkelectronics.com/linux+v3.12/arch/x86/include/asm/processor.h#L470

Pole error_code nie jest eksportowana do siginfo_t struct jak widzę (jest on określony w http://man7.org/linux/man-pages/man2/sigaction.2.html .. szukać si_signo).

Więc można

  • Hack jądra eksportu tsk->thread.error_code (lub sprawdzić, czy jest eksportowana już, czy nie, na przykład w ptrace)
  • uzyskać adres pamięci, przeczytaj /proc/self/maps, analizować je i czek bity dostępu na stronie. Jeśli strona jest obecna i jest tylko do odczytu, jedyną możliwą usterką jest pisanie, jeśli strona nie jest dostępna, oba rodzaje dostępu są możliwe, a jeśli ... nie powinno być stron tylko do zapisu.
  • Możesz również spróbować znaleźć adres nieudanej instrukcji, przeczytać ją i rozmontować.
+2

Dostęp do informacji o kodzie błędu można uzyskać przez: (kontekst (ucontext_t *)) -> uc_mcontext.gregs [REG_ERR]. Jest przekazywany przez sprzęt na stosie, który jest następnie przekazywany do obsługi sygnału przez jądro, ponieważ jądro przechodzi przez całą "ramkę". –

+0

M. Alaggan, jaki sprzęt? – osgx

+0

Próbowałem go na x86-64. –

3

Można to sprawdzić w x86_64 odwołując się do mcontext struktury w ucontext i rejestrze ERR:

void pf_sighandler(int sig, siginfo_t *info, ucontext_t *ctx) { 
    ... 
    if (ctx->uc_mcontext.gregs[REG_ERR] & 0x2) { 
     // Write fault 
    } else { 
     // Read fault 
    } 
    ... 
} 
4

Informacje kod_błędu można uzyskać poprzez:

err = ((ucontext_t*)context)->uc_mcontext.gregs[REG_ERR] 

jest on przekazywany przez sprzęt na stosie, który następnie jest przekazywany do obsługi sygnału przez jądro, ponieważ jądro przechodzi przez całą "ramkę". Następnie będzie prawdą, jeśli dostęp był prawem do zapisu, a false w przeciwnym razie.