Пример #1
0
static int set_guard_page(port_tls_data_t* tlsdata, Boolean set)
{
    int res;

    if (!tlsdata)
        tlsdata = get_private_tls_data();
	
    if (!tlsdata)
        return -1;

    if (!tlsdata->guard_page_addr)
        return 0;

    if ((set && tlsdata->guard_page_set) ||
        (!set && !tlsdata->guard_page_set))
        return 0; // Already in needed state

    res = mprotect(tlsdata->guard_page_addr, tlsdata->guard_page_size,
                    set ? PROT_NONE : (PROT_READ | PROT_WRITE | PROT_EXEC));

	
    if (res != 0)
        return errno;

    if (set)
    {
        res = set_alt_stack(tlsdata, TRUE);

        if (res != 0)
            return res;
    }

    tlsdata->guard_page_set = set;
    return 0;
}
Пример #2
0
static void c_handler(Registers* pregs, size_t signum, void* fault_addr)
{   // this exception handler is executed *after* OS signal handler returned
    int result;
    port_tls_data_t* tlsdata = get_private_tls_data();

    switch ((int)signum)
    {
    case SIGSEGV:
        if (tlsdata->restore_guard_page)
        {
            // Now it's safe to disable alternative stack
            set_alt_stack(tlsdata, FALSE);
            result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, pregs, fault_addr, FALSE);
        }
        else
            result = port_process_signal(PORT_SIGNAL_GPF, pregs, fault_addr, FALSE);
        break;
    case SIGFPE:
        result = port_process_signal(PORT_SIGNAL_ARITHMETIC, pregs, fault_addr, FALSE);
        break;
    case SIGTRAP:
        // Correct return address
        pregs->set_ip((void*)((POINTER_SIZE_INT)pregs->get_ip() - 1));
        result = port_process_signal(PORT_SIGNAL_BREAKPOINT, pregs, fault_addr, FALSE);
        break;
    case SIGINT:
        result = port_process_signal(PORT_SIGNAL_CTRL_C, pregs, fault_addr, FALSE);
        break;
    case SIGQUIT:
        result = port_process_signal(PORT_SIGNAL_QUIT, pregs, fault_addr, FALSE);
        break;
    case SIGABRT:
        result = port_process_signal(PORT_SIGNAL_ABORT, NULL, fault_addr, FALSE);
        break;
    default:
        result = port_process_signal(PORT_SIGNAL_UNKNOWN, pregs, fault_addr, TRUE);
    }

    if (result == 0)
    {
        // Restore guard page if needed
        if (tlsdata->restore_guard_page)
        {
            port_thread_restore_guard_page();
            tlsdata->restore_guard_page = FALSE;

            if (port_thread_detach_temporary() == 0)
                STD_FREE(tlsdata);
        }
        return;
    }

    // We've got a crash
    if (signum == SIGSEGV)
    {
        port_thread_restore_guard_page(); // To catch SO again
        tlsdata->restore_guard_page = FALSE;
    }

    if (result > 0) // invoke debugger
    {   // Prepare second catch of signal to attach GDB from signal handler
        //assert(tlsdata); // Should be attached - provided by general_signal_handler
        tlsdata->debugger = TRUE;
        return; // To produce signal again
    }

    // result < 0 - exit process
    if (FLAG_CORE)
    {   // Return to the same place to produce the same crash and generate core
        signal(signum, SIG_DFL); // setup default handler
        return;
    }

    // No core needed - simply terminate
    _exit(-1);
}