def watchRunProgram(self, pid): usingMem = 0 while True: wpid, status, res = os.wait4(pid,0) signal.signal(signal.SIGXCPU, self.sigHandler) # 정상 종료된 경우 if os.WIFEXITED(status): return 'Grading', res[0], usingMem exitCode = os.WEXITSTATUS(status) # 종료 코드에 따라 return if exitCode is 24: return ENUMResources.const.TIME_OVER, res[0], usingMem elif exitCode is not 5 and exitCode is not 0 and exitCode is not 17: return ENUMResources.const.RUNTIME_ERROR, 0, 0 elif os.WIFSIGNALED(status): try: ptrace.kill(pid) except Exception as e: pass return ENUMResources.const.RUNTIME_ERROR, 0, 0 # 메모리 사용량 측정 else: usingMem = self.getUsingMemory(pid, usingMem, res[6]) ptrace.syscall(pid, 0)
def watchRunProgram(self, pid): usingMem = 0 while True: wpid, status, res = os.wait4(pid, 0) signal.signal(signal.SIGXCPU, self.sigHandler) # 정상 종료된 경우 if os.WIFEXITED(status): return 'Grading', res[0], usingMem exitCode = os.WEXITSTATUS(status) # 종료 코드에 따라 return if exitCode is 24: return ENUMResources.const.TIME_OVER, res[0], usingMem elif exitCode is not 5 and exitCode is not 0 and exitCode is not 17: return ENUMResources.const.RUNTIME_ERROR, 0, 0 elif os.WIFSIGNALED(status): try: ptrace.kill(pid) except Exception as e: pass return ENUMResources.const.RUNTIME_ERROR, 0, 0 # 메모리 사용량 측정 else: usingMem = self.getUsingMemory(pid, usingMem, res[6]) ptrace.syscall(pid, 0)
def trace_syscall(pid, flags, tricklist): scno = ptrace.peekuser(pid, ORIG_EAX) assert (0 <= scno < len(syscallmap.table) or scno == _badcall or flags.has_key('sigreturn')), \ "unknown system call (=%s, pid=%s, flags=%s)" % (scno, pid, flags) if scno == _badcall: call = 'badcall' elif flags.has_key('sigreturn'): call = flags['sigreturn'] # !beforecall else: sysent = syscallmap.table[scno] call = sysent[syscallmap.CALL] eax = ptrace.peekuser(pid, EAX) beforecall = not flags.has_key('insyscall') if eax != -errno.ENOSYS and beforecall: # XXX: is this test right? if call == 'execve' and debug(): print 'debug: ignoring additional execve stop' return if 0 <= eax <= len(syscallmap.table): eaxcall = syscallmap.table[eax][3] else: eaxcall = "" # FIX: this probably fires for SIG_DFL stop calls (except SIGSTOP) print 'warning: received SIGTRAP or stray syscall exit: eax = %d (%s)' % ( eax, eaxcall) # FIX: is this right? what's really going on here? # no, don't do this, because of the SIG_DFL issue above!!!!! --mkc #raise 'warning: received SIGTRAP or stray syscall exit:' \ # 'pid = %d, eax = %d (%s)' % (pid, eax, eaxcall) #return # FIX: is this the right thing to do? flags['insyscall'] = 1 flags['state'] = {} flags['call_changes'] = {} global _skipcallafter if beforecall: if not _call_weedout_mask[scno]: _skipcallafter[pid] = 1 flags['insyscall'] = 1 ptrace.syscall(pid, 0) return return trace_syscall_before(pid, flags, tricklist, call, scno, sysent) if _skipcallafter.has_key(pid): del _skipcallafter[pid] del flags['insyscall'] ptrace.syscall(pid, 0) return return trace_syscall_after(pid, flags, tricklist, call, eax)
def trace_syscall(pid, flags, tricklist): scno = ptrace.peekuser(pid, ORIG_EAX) assert ( 0 <= scno < len(syscallmap.table) or scno == _badcall or flags.has_key("sigreturn") ), "unknown system call (=%s, pid=%s, flags=%s)" % (scno, pid, flags) if scno == _badcall: call = "badcall" elif flags.has_key("sigreturn"): call = flags["sigreturn"] # !beforecall else: sysent = syscallmap.table[scno] call = sysent[syscallmap.CALL] eax = ptrace.peekuser(pid, EAX) beforecall = not flags.has_key("insyscall") if eax != -errno.ENOSYS and beforecall: # XXX: is this test right? if call == "execve" and debug(): print "debug: ignoring additional execve stop" return if 0 <= eax <= len(syscallmap.table): eaxcall = syscallmap.table[eax][3] else: eaxcall = "" # FIX: this probably fires for SIG_DFL stop calls (except SIGSTOP) print "warning: received SIGTRAP or stray syscall exit: eax = %d (%s)" % (eax, eaxcall) # FIX: is this right? what's really going on here? # no, don't do this, because of the SIG_DFL issue above!!!!! --mkc # raise 'warning: received SIGTRAP or stray syscall exit:' \ # 'pid = %d, eax = %d (%s)' % (pid, eax, eaxcall) # return # FIX: is this the right thing to do? flags["insyscall"] = 1 flags["state"] = {} flags["call_changes"] = {} global _skipcallafter if beforecall: if not _call_weedout_mask[scno]: _skipcallafter[pid] = 1 flags["insyscall"] = 1 ptrace.syscall(pid, 0) return return trace_syscall_before(pid, flags, tricklist, call, scno, sysent) if _skipcallafter.has_key(pid): del _skipcallafter[pid] del flags["insyscall"] ptrace.syscall(pid, 0) return return trace_syscall_after(pid, flags, tricklist, call, eax)
def force_syscall(pid, scno, p1=0, p2=0, p3=0, p4=0, p5=0, p6=0): registers = peek_args(pid, 6) eip = ptrace.peekuser(pid, EIP) eax = ptrace.peekuser(pid, EAX) ptrace.pokeuser(pid, EIP, eip - 2) ptrace.pokeuser(pid, EAX, scno) # Select new scno and point eip to syscall poke_args(pid, 6, [p1, p2, p3, p4, p5, p6]) ptrace.syscall(pid, 0) # We make it return to userland and do syscal wpid, status = os.waitpid(pid, wait_flags) assert pid == wpid ptrace.syscall(pid, 0) # Kernel stops us before syscall is done wpid, status = os.waitpid(pid, wait_flags) if wpid != pid: print "problem: other syscall stopped woke up /2: ", pid, " != ", wpid assert pid == wpid # Kernel stops us when syscall is done res = ptrace.peekuser(pid, EAX) # We get the syscall result ptrace.pokeuser(pid, EAX, eax) # and then mimic like nothing happened poke_args(pid, 6, registers) return res
def __traceProgram(self, pid): while True: wpid, status, res = os.wait4(pid, 0) # normal termination if os.WIFEXITED(status): return True, res[0] # abnormal termination elif os.WIFSIGNALED(status): try: ptrace.kill(pid) except Exception as e: pass return RUNTIME_ERROR, res[0] else: ptrace.syscall(pid, 0)
def WatchRunProgram(self, pid): usingMem = 0 while True: wpid, status, res = os.wait4(pid,0) if os.WIFEXITED(status): return 'Grading', res[0], usingMem exitCode = os.WEXITSTATUS(status) if exitCode != 5 and exitCode != 0 and exitCode != 17: return ENUMResources.const.RUNTIME_ERROR, 0, 0 elif os.WIFSIGNALED(status): return ENUMResources.const.TIME_OVER, res[0], usingMem else: usingMem = self.GetUsingMemory(pid, usingMem) ptrace.syscall(pid, 0)
if flags.has_key('startup'): # XXX: This is a slight race, as we're assuming this is the # SIGTRAP after first exec. # Hmm: is this an early chance to do something interesting? try: ptrace.settracesysgood(wpid) except OSError, e: if e.errno == errno.EIO: # kernel doesn't have this patch (which means it'd # better have the old one) if debug(): print "warning: using tracesysgood backward compatibility mode" else: sys.exit("%s settracesysgood error [%s]" % (sys.argv[0], e)) ptrace.syscall(wpid, 0) del flags['startup'] continue stopsig = os.WSTOPSIG(status) if waitchannelhack: callstop = _subterfugue.atcallstop(wpid, stopsig) else: callstop = stopsig == signal.SIGTRAP | 0x80 if not callstop: sig = trace_signal(wpid, flags, tricklist, stopsig) if (sig == signal.SIGSTOP or sig == signal.SIGTSTP or sig == signal.SIGTTIN or sig == signal.SIGTTOU): # FIX: more needed for ~SIGSTOP case
def trace_syscall_after(pid, flags, tricklist, call, eax): result = eax state = flags["state"] call_changes = flags["call_changes"] # del flags['call_changes'] # ? # FIX: copy/reverse slow? tricklist = tricklist[:] # do callafters for tricks we did callbefores on, in reverse order, # minus the annulled trick (if any) if flags.has_key("annul"): result, annultrick = flags["annul"] assert isinstance(result, types.IntType), "oops: waitsuspend not cleared?" del flags["annul"] call = call_changes[annultrick] while tricklist and tricklist.pop()[0] != annultrick: pass elif flags.has_key("sigreturn"): # we have to do this because ORIG_EAX somehow gets stomped by the # sigreturn calls. maybe this is a kernel bug? call = flags["sigreturn"] del flags["sigreturn"] tricklist.reverse() memory = getMemory(pid) for trick, callmask, signalmask in tricklist: call = call_changes.get(trick, call) if (not callmask or callmask.has_key(call)) and trick.is_enabled(pid): r = trick.callafter(pid, call, result, state.get(trick)) if r != None: result = r memory.pop(trick) assert memory.empty() # all momentary changes got popped if result != eax: if debug(): print "ptrace.pokeuser(%s, %s, %s)" % (pid, EAX, result) ptrace.pokeuser(pid, EAX, result) # undo any changes to child's args made on entry # XXX: does this go here? for n, arg in flags.get("args_delta", []): if debug(): print "ptrace.pokeuser(%s, %s, %s)" % (pid, 4 * n, arg) ptrace.pokeuser(pid, 4 * n, arg) call_save = flags.get("call_delta", -1) if call_save >= 0: if debug(): print "ptrace.pokeuser(%s, %s, %s)" % (pid, ORIG_EAX, call_save) ptrace.pokeuser(pid, ORIG_EAX, call_save) # could continue child hereabouts ptrace.syscall(pid, 0) if flags.has_key("call_delta"): del flags["call_delta"] if flags.has_key("args_delta"): del flags["args_delta"] del flags["insyscall"]
if isinstance(call, types.StringType): callno = syscallmap.lookup_number(call) else: callno = call try: if debug(): print "ptrace.pokeuser(%s, %s, %s)" % (pid, ORIG_EAX, callno) ptrace.pokeuser(pid, ORIG_EAX, callno) flags["call_delta"] = scno except OSError, e: # FIX: do something better here sys.exit("panic: call alter failed in trick %s (%s)" % (trick, e)) # could continue child hereabouts ptrace.syscall(pid, 0) flags["state"] = state flags["insyscall"] = 1 if flags.has_key("newchild"): assert call == "clone" newppid, tag = flags["newchild"] # FIX: better way to pass these back? del flags["newchild"] # XXX: deep copy causes a problem? CHECK THIS f = copy.copy(flags) f["newchildflags"] = {} f["children"] = [] if newppid == pid: f["parent"] = pid f["exit_signal"] = args[0] & clone.CSIGNAL return (newppid, tag, f)
# XXX: This is a slight race, as we're assuming this is the # SIGTRAP after first exec. # Hmm: is this an early chance to do something interesting? try: ptrace.settracesysgood(wpid) except OSError, e: if e.errno == errno.EIO: # kernel doesn't have this patch (which means it'd # better have the old one) if debug(): print "warning: using tracesysgood backward compatibility mode" else: sys.exit("%s settracesysgood error [%s]" % (sys.argv[0], e)) ptrace.syscall(wpid, 0) del flags['startup'] continue stopsig = os.WSTOPSIG(status) if waitchannelhack: callstop = _subterfugue.atcallstop(wpid, stopsig) else: callstop = stopsig == signal.SIGTRAP | 0x80 if not callstop: sig = trace_signal(wpid, flags, tricklist, stopsig) if (sig == signal.SIGSTOP or sig == signal.SIGTSTP or sig == signal.SIGTTIN or sig == signal.SIGTTOU): # FIX: more needed for ~SIGSTOP case
def trace_syscall_after(pid, flags, tricklist, call, eax): result = eax state = flags['state'] call_changes = flags['call_changes'] #del flags['call_changes'] # ? # FIX: copy/reverse slow? tricklist = tricklist[:] # do callafters for tricks we did callbefores on, in reverse order, # minus the annulled trick (if any) if flags.has_key('annul'): result, annultrick = flags['annul'] assert isinstance(result, types.IntType), "oops: waitsuspend not cleared?" del flags['annul'] call = call_changes[annultrick] while tricklist and tricklist.pop()[0] != annultrick: pass elif flags.has_key('sigreturn'): # we have to do this because ORIG_EAX somehow gets stomped by the # sigreturn calls. maybe this is a kernel bug? call = flags['sigreturn'] del flags['sigreturn'] tricklist.reverse() memory = getMemory(pid) for trick, callmask, signalmask in tricklist: call = call_changes.get(trick, call) if (not callmask or callmask.has_key(call)) \ and trick.is_enabled(pid): r = trick.callafter(pid, call, result, state.get(trick)) if r != None: result = r memory.pop(trick) assert memory.empty() # all momentary changes got popped if result != eax: if debug(): print "ptrace.pokeuser(%s, %s, %s)" % (pid, EAX, result) ptrace.pokeuser(pid, EAX, result) # undo any changes to child's args made on entry # XXX: does this go here? for n, arg in flags.get('args_delta', []): if debug(): print "ptrace.pokeuser(%s, %s, %s)" % (pid, 4 * n, arg) ptrace.pokeuser(pid, 4 * n, arg) call_save = flags.get('call_delta', -1) if call_save >= 0: if debug(): print "ptrace.pokeuser(%s, %s, %s)" % (pid, ORIG_EAX, call_save) ptrace.pokeuser(pid, ORIG_EAX, call_save) # could continue child hereabouts ptrace.syscall(pid, 0) if flags.has_key('call_delta'): del flags['call_delta'] if flags.has_key('args_delta'): del flags['args_delta'] del flags['insyscall']
if isinstance(call, types.StringType): callno = syscallmap.lookup_number(call) else: callno = call try: if debug(): print "ptrace.pokeuser(%s, %s, %s)" % (pid, ORIG_EAX, callno) ptrace.pokeuser(pid, ORIG_EAX, callno) flags['call_delta'] = scno except OSError, e: # FIX: do something better here sys.exit('panic: call alter failed in trick %s (%s)' % (trick, e)) # could continue child hereabouts ptrace.syscall(pid, 0) flags['state'] = state flags['insyscall'] = 1 if flags.has_key('newchild'): assert call == 'clone' newppid, tag = flags['newchild'] # FIX: better way to pass these back? del flags['newchild'] # XXX: deep copy causes a problem? CHECK THIS f = copy.copy(flags) f['newchildflags'] = {} f['children'] = [] if newppid == pid: f['parent'] = pid f['exit_signal'] = args[0] & clone.CSIGNAL return (newppid, tag, f)