Exemple #1
0
PCEventHandler::RTSignalResult
PCEventHandler::handleRTSignal(EventSignal::const_ptr ev, PCProcess *evProc) const {
    // Check whether the signal was sent from the RT library by checking variables
    // in the library -- if we cannot be determine whether this signal came from
    // the RT library, assume it did not.
    
    if( evProc->runtime_lib.size() == 0 ) return NotRTSignal;

    Address sync_event_breakpoint_addr = evProc->getRTEventBreakpointAddr();
    Address sync_event_id_addr = evProc->getRTEventIdAddr();
    Address sync_event_arg1_addr = evProc->getRTEventArg1Addr();

    int breakpoint = 0;
    int status = 0;
    Address arg1 = 0;
    int zero = 0;

    // Check that all addresses could be determined
    if(    sync_event_breakpoint_addr == 0 
        || sync_event_id_addr == 0 
        || sync_event_arg1_addr == 0 ) 
    {
        return NotRTSignal;
    }

    // First, check breakpoint...
    if( !evProc->readDataWord((const void *)sync_event_breakpoint_addr,
                sizeof(int), &breakpoint, false) ) return NotRTSignal;

    switch(breakpoint) {
        case NoRTBreakpoint:
            proccontrol_printf("%s[%d]: signal is not RT library signal\n",
                    FILE__, __LINE__);
            return NotRTSignal;
        case NormalRTBreakpoint:
        case SoftRTBreakpoint:
            // More work to do
            break;
        default:
            proccontrol_printf("%s[%d]: invalid value for RT library breakpoint variable\n",
                    FILE__, __LINE__);
            return NotRTSignal;
    }

    // Make sure we don't get this event twice....
    if( !evProc->writeDataWord((void *)sync_event_breakpoint_addr, sizeof(int), &zero) ) {
        proccontrol_printf("%s[%d]: failed to reset RT library breakpoint variable\n",
                FILE__, __LINE__);
        return NotRTSignal;
    }

    // Get the type of the event
    if( !evProc->readDataWord((const void *)sync_event_id_addr, sizeof(int),
                &status, false) ) return NotRTSignal;

    if( status == DSE_undefined ) {
        proccontrol_printf("%s[%d]: signal is not RT library signal\n", FILE__, __LINE__);
        return NotRTSignal;
    }

    // get runtime library arg1 address
    if( !evProc->readDataWord((const void *)sync_event_arg1_addr,
                evProc->getAddressWidth(), &arg1, false) ) {
        proccontrol_printf("%s[%d]: failed to read RT library arg1 variable\n",
                FILE__, __LINE__);
        return NotRTSignal;
    }

    if( !isValidRTSignal(ev->getSignal(), (RTBreakpointVal) breakpoint, arg1, status) ) return NotRTSignal;

    BPatch_process *bproc = BPatch::bpatch->getProcessByPid(evProc->getPid());
    if( bproc == NULL ) {
        proccontrol_printf("%s[%d]: no corresponding BPatch_process for process %d\n",
                FILE__, __LINE__, evProc->getPid());
        return ErrorInDecoding;
    }

    // See pcEventHandler.h (SYSCALL HANDLING) for a description of what
    // is going on here

    Event::ptr newEvt;

    switch(status) {
    case DSE_forkEntry:
        proccontrol_printf("%s[%d]: decoded forkEntry, arg = %lx\n",
                      FILE__, __LINE__, arg1);
		if (PCEventMuxer::useBreakpoint(EventType(EventType::Pre, EventType::Fork)))
		{
                proccontrol_printf("%s[%d]: reporting fork entry event to BPatch layer\n",
                        FILE__, __LINE__);
                BPatch::bpatch->registerForkingProcess(evProc->getPid(), NULL);
              
        }
        break;
    case DSE_forkExit:
        proccontrol_printf("%s[%d]: decoded forkExit, arg = %lx\n",
                      FILE__, __LINE__, arg1);
		if (PCEventMuxer::useBreakpoint(EventType(EventType::Post, EventType::Fork))) {
                proccontrol_printf("%s[%d]: reporting fork exit event to ProcControlAPI\n",
                        FILE__, __LINE__);
                newEvt = Event::ptr(new EventFork(EventType::Pre, (Dyninst::PID)arg1));
        }
        break;
    case DSE_execEntry:
        proccontrol_printf("%s[%d]: decoded execEntry, arg = %lx\n",
                      FILE__, __LINE__, arg1);
        // For now, just note that the process is going to exec
        evProc->setExecing(true);
        break;
    case DSE_execExit:
        proccontrol_printf("%s[%d]: decoded execExit, arg = %lx\n",
                      FILE__, __LINE__, arg1);
        // This is not currently used by Dyninst internals for anything
        // We rely on ProcControlAPI for this and it should be impossible
        // to get this via a breakpoint
        return ErrorInDecoding;
    case DSE_exitEntry:
        proccontrol_printf("%s[%d]: decoded exitEntry, arg = %lx\n",
                      FILE__, __LINE__, arg1);
        /* Entry of exit, used for the callback. We need to trap before
           the process has actually exited as the callback may want to
           read from the process */
		if (PCEventMuxer::useBreakpoint(EventType(EventType::Pre, EventType::Exit))) {
			if (PCEventMuxer::useCallback(EventType(EventType::Pre, EventType::Exit))) {
                proccontrol_printf("%s[%d]: reporting exit entry event to ProcControlAPI\n",
                        FILE__, __LINE__);
                newEvt = Event::ptr(new EventExit(EventType::Pre, (int)arg1));
			}
			else {
                proccontrol_printf("%s[%d]: reporting exit entry event to BPatch layer\n",
                        FILE__, __LINE__);
                evProc->triggerNormalExit((int)arg1);
			}
        }
        break;
    case DSE_loadLibrary:
        proccontrol_printf("%s[%d]: decoded loadLibrary (error), arg = %lx\n",
                      FILE__, __LINE__, arg1);
        // This is no longer used
        return ErrorInDecoding;
    case DSE_lwpExit:
        proccontrol_printf("%s[%d]: decoded lwpExit (error), arg = %lx\n",
                      FILE__, __LINE__, arg1);
        // This is not currently used on any platform
        return ErrorInDecoding;
    case DSE_snippetBreakpoint:
        proccontrol_printf("%s[%d]: decoded snippetBreak, arg = %lx\n",
                      FILE__, __LINE__, arg1);
        bproc->setLastSignal(ev->getSignal());
        evProc->setDesiredProcessState(PCProcess::ps_stopped);
        break;
    case DSE_stopThread:
        proccontrol_printf("%s[%d]: decoded stopThread, arg = %lx\n",
                      FILE__, __LINE__, arg1);
        bproc->setLastSignal(ev->getSignal());
        if( !handleStopThread(evProc, arg1) ) {
            proccontrol_printf("%s[%d]: failed to handle stopped thread event\n",
                    FILE__, __LINE__);
            return ErrorInDecoding;
        }
        break;
    case DSE_dynFuncCall:
        proccontrol_printf("%s[%d]: decoded dynamic callsite event, arg = %lx\n",
                FILE__, __LINE__, arg1);
        if( !handleDynFuncCall(evProc, bproc, arg1) ) {
            proccontrol_printf("%s[%d]: failed to handle dynamic callsite event\n",
                    FILE__, __LINE__);
            return ErrorInDecoding;
        }
        break;
    case DSE_userMessage:
        proccontrol_printf("%s[%d]: decoded user message event, arg = %lx\n",
                FILE__, __LINE__, arg1);
        if( !handleUserMessage(evProc, bproc, arg1) ) {
            proccontrol_printf("%s[%d]: failed to handle user message event\n",
                    FILE__, __LINE__);
            return ErrorInDecoding;
        }
        break;
    default:
        return NotRTSignal;
    }

    // Behavior common to all syscalls
    if( newEvt != NULL ) {
        // Report the event to ProcControlAPI, make sure process remains stopped
        evProc->setReportingEvent(true);

        newEvt->setProcess(ev->getProcess());
        newEvt->setThread(ev->getThread());

        // In the callback thread, the process and thread are stopped
        newEvt->setSyncType(Event::sync_process);
        newEvt->setUserEvent(true);

        ProcControlAPI::mbox()->enqueue(newEvt);
    }

    return IsRTSignal;
}
Exemple #2
0
bool PCEventHandler::handleSignal(EventSignal::const_ptr ev, PCProcess *evProc) const {
    proccontrol_printf("%s[%d]: thread %d/%d received signal %d\n",
            FILE__, __LINE__, ev->getProcess()->getPid(), ev->getThread()->getLWP(),
            ev->getSignal());

    // Check whether it is a signal from the RT library (note: this will internally
    // handle any entry/exit to syscalls and make the necessary up calls as appropriate)
    RTSignalResult result = handleRTSignal(ev, evProc);
    if( result == ErrorInDecoding ) {
        proccontrol_printf("%s[%d]: failed to determine whether signal came from RT library\n",
                FILE__, __LINE__);
        return false;
    }

    if( result == IsRTSignal ) {
        // handleRTSignal internally does all handling for the events in order to keep
        // related logic in one place
        proccontrol_printf("%s[%d]: signal came from RT library\n", FILE__, __LINE__);
        return true;
    }

    // check if windows access violation, defensive mode, and write permissions.
    // unprotect pages if necessary.
    if (evProc->getHybridMode() == BPatch_defensiveMode 
        && ev->isFirst() 
        && ev->getCause() == EventSignal::WriteViolation) {
            malware_cerr << "Write to protected address 0x" << std::hex 
                << ev->getAddress() << std::dec << std::endl;
            Address addr = ev->getAddress();
            mapped_object* obj = evProc->findObject(addr);

            // retry finding object by its original address.
            if (obj == NULL && evProc->isMemoryEmulated()) {
                std::pair<bool, Address> trans = 
                    evProc->getMemEm()->translateBackwards(addr);
                if (trans.first) { 
                    addr = trans.second;
                    obj = evProc->findObject(addr);
                }
            }

            // change permissions if we can find this originally writable region
            if (obj != NULL) {
                SymtabAPI::Region* reg = 
                    obj->parse_img()->getObject()->findEnclosingRegion(addr - obj->codeBase());
                if (reg != NULL && (reg->getRegionPermissions() == SymtabAPI::Region::RP_RW
                            || reg->getRegionPermissions() == SymtabAPI::Region::RP_RWX)) {
                        // change back permissions.
                        PCProcess::PCMemPerm rights(true, true, true);
                        evProc->changeMemoryProtections(
                            addr - (addr % evProc->getMemoryPageSize()), 
                            evProc->getMemoryPageSize(), 
                            rights /* PAGE_EXECUTE_READWRITE */ , 
                            false);
                        return true;
                }
            }

            // else fall through to forwarding.
    }

    bool shouldForwardSignal = true;

    BPatch_process *bpproc = BPatch::bpatch->getProcessByPid(evProc->getPid());
    if( bpproc == NULL ) {
        proccontrol_printf("%s[%d]: failed to locate BPatch_process for process %d\n",
                FILE__, __LINE__, evProc->getPid());
    }

    if( shouldStopForSignal(ev->getSignal()) ) {
        proccontrol_printf("%s[%d]: signal %d is stop signal, leaving process stopped\n",
                FILE__, __LINE__, ev->getSignal());
        evProc->setDesiredProcessState(PCProcess::ps_stopped);
        shouldForwardSignal = false;
    }

    // Tell the BPatch layer we received a signal
    if( bpproc ) bpproc->setLastSignal(ev->getSignal());

    // Debugging only
    if(    (dyn_debug_proccontrol || dyn_debug_crash)
            && isCrashSignal(ev->getSignal()) ) {
        fprintf(stderr, "Caught crash signal %d for thread %d/%d\n",
                ev->getSignal(), ev->getProcess()->getPid(), ev->getThread()->getLWP());

        RegisterPool regs;
        if( !ev->getThread()->getAllRegisters(regs) ) {
            fprintf(stderr, "%s[%d]: Failed to get registers for crash\n", FILE__, __LINE__);
        }else{
            fprintf(stderr, "Registers at crash:\n");
            for(RegisterPool::iterator i = regs.begin(); i != regs.end(); i++) {
                fprintf(stderr, "\t%s = 0x%lx\n", (*i).first.name().c_str(), (*i).second);
            }
        }

        // Dump the stacks
        pdvector<pdvector<Frame> > stackWalks;
        evProc->walkStacks(stackWalks);
        for (unsigned walk_iter = 0; walk_iter < stackWalks.size(); walk_iter++) {
            fprintf(stderr, "Stack for pid %d, lwpid %d\n",
                    stackWalks[walk_iter][0].getProc()->getPid(),
                    stackWalks[walk_iter][0].getThread()->getLWP());
            for( unsigned i = 0; i < stackWalks[walk_iter].size(); i++ ) {
                cerr << stackWalks[walk_iter][i] << endl;
            }
        }

        // User specifies the action, defaults to core dump
        // (which corresponds to standard Dyninst behavior)
        if(dyn_debug_crash_debugger) {
            if( string(dyn_debug_crash_debugger).find("gdb") != string::npos ) {
                evProc->launchDebugger();

                // If for whatever reason this fails, fall back on sleep
                dyn_debug_crash_debugger = const_cast<char *>("sleep");
            }

            if( string(dyn_debug_crash_debugger) == string("sleep") ) {
                static volatile int spin = 1;
                while(spin) sleep(1);
            }
        }
    }

    if(shouldForwardSignal ) {
        // Now, explicitly set the signal to be delivered to the process
        ev->setThreadSignal(ev->getSignal());
    }

    return true;
}