How to identify read or write operations of page fault when using sigaction handler on SIGSEGV?(LINUX)
Asked Answered
F

3

8

I use sigaction to handle page fault exception, and the handler function is defind like this:

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

So it's easy to get page fault address by reading info->si_addr.

The question is, how to know whether this operation is memory READ or WRITE ?

I found the type of _context parameter is ucontext_t defined in /usr/include/sys/ucontext.h

There is a cr2 field defined in mcontext_t, but unforunately, it is only avaliable when x86_64 is not defind, thus I could not used cr2 to identify read/write operations.

On anotherway, there is a struct named sigcontext defined in /usr/include/bits/sigcontext.h This struct contains cr2 field. But I don't know where to get it.

Fracture answered 16/7, 2013 at 8:43 Comment(0)
D
7

You can check this in x86_64 by referring to the ucontext's mcontext struct and the err register:

void pf_sighandler(int sig, siginfo_t *info, ucontext_t *ctx) {
    ...
    if (ctx->uc_mcontext.gregs[REG_ERR] & 0x2) {
        // Write fault
    } else {
        // Read fault
    }
    ...
}
Dvina answered 27/4, 2014 at 20:58 Comment(0)
G
6

Here is the generation of SIGSEGV from the kernel arch/x86/mm/fault.c, __bad_area_nosemaphore() function: 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);

There is error_code field, and it values are defined in arch/x86/mm/fault.c too: 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};

So, exact information about access type is stored in the thread_struct.error_code: http://lxr.missinglinkelectronics.com/linux+v3.12/arch/x86/include/asm/processor.h#L470

The error_code field is not exported into siginfo_t struct as I see (it is defined in http://man7.org/linux/man-pages/man2/sigaction.2.html .. search for si_signo).

So you can

  • Hack the kernel to export tsk->thread.error_code (or check, is it exported already or not, for example in ptrace)
  • Get the memory address, read /proc/self/maps, parse them and check access bits on the page. If the page is present and read-only, the only possible fault is from writing, if page is not present both kinds of access are possible, and if... there should be no write-only pages.
  • Also you can try to find the address of failed instruction, read it and disassemble.
Globetrotter answered 19/4, 2014 at 0:12 Comment(2)
The error_code information can be accessed through: ((ucontext_t*)context)->uc_mcontext.gregs[REG_ERR]. It is passed by the hardware on the stack, which is then passed to the signal handler by the kernel, since the kernel passes the entire `frame'.Hedgehog
M. Alaggan, which hardware?Globetrotter
H
5

The error_code information can be accessed through:

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

It is passed by the hardware on the stack, which is then passed to the signal handler by the kernel, since the kernel passes the entire `frame'. Then

bool write_fault = !(err & 0x2);

will be true if the access was a write access, and false otherwise.

Hedgehog answered 26/12, 2014 at 14:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.