static VOID SyscallEntry(THREADID threadIndex, CONTEXT *ctxt, SYSCALL_STANDARD std, VOID *v) { if (PIN_GetSyscallNumber(ctxt, std) != SYS_sysarch) return; ADDRINT pc = PIN_GetContextReg(ctxt, REG_INST_PTR); ADDRINT op = PIN_GetSyscallArgument(ctxt, std, 0); ADDRINT addr = PIN_GetSyscallArgument(ctxt, std, 1); ADDRINT value = 0; if (op == AMD64_SET_FSBASE || op == AMD64_SET_GSBASE) { if (PIN_SafeCopy(&value, Addrint2VoidStar(addr), sizeof(ADDRINT)) != sizeof(ADDRINT)) { Out << Header(threadIndex, pc) << "Failed to read actual TLS pointer" << endl; } } else { // Remember the location where to write the segment register in REG_INST_G0 PIN_SetContextReg(ctxt, REG_INST_G0, addr); value = addr; } Out << Header(threadIndex, pc) << "sysarch(" << SysArchFunc(op) << ", 0x" << std::hex << value << ")" << std::endl; }
VOID OnSyscallEntry(THREADID threadIndex, CONTEXT *ctxt, SYSCALL_STANDARD std, VOID *v) { ADDRINT sysnum = PIN_GetSyscallNumber(ctxt, std); ADDRINT arg0 = PIN_GetSyscallArgument(ctxt, std, 0); #ifdef TARGET_BSD // If this is the system call dispatcher, then use arg0 as the system call number if (sysnum == SYS___syscall) { sysnum = arg0; arg0 = PIN_GetSyscallArgument(ctxt, std, 1); } #endif if (sysnum == SYS_open && strncmp(reinterpret_cast<char *>(arg0), "does-not-exist1", sizeof("does-not-exist1")-1) == 0) { PIN_SetSyscallNumber(ctxt, std, SYS_getpid); } if (IsSigaction(sysnum) && (arg0 == SIGUSR1)) { PIN_SetSyscallNumber(ctxt, std, SYS_getpid); } if (sysnum == SYS_open && strncmp(reinterpret_cast<char *>(arg0), "does-not-exist2", sizeof("does-not-exist2")-1) == 0) { PIN_SetSyscallNumber(ctxt, std, SYS_exit); PIN_SetSyscallArgument(ctxt, std, 0, 0); } }
FutexInfo PrePatchFutex(uint32_t tid, CONTEXT* ctxt, SYSCALL_STANDARD std) { FutexInfo fi; fi.op = (int) PIN_GetSyscallArgument(ctxt, std, 1); fi.val = (int) PIN_GetSyscallArgument(ctxt, std, 2); if (isFutexWakeOp(fi.op)) { zinfo->sched->notifyFutexWakeStart(procIdx, tid, fi.val); } return fi; }
static bool PrePatchTimeoutSyscall(uint32_t tid, CONTEXT* ctxt, SYSCALL_STANDARD std, int syscall) { assert(!inFakeTimeoutMode[tid]); // canary: this will probably fail... int64_t waitNsec = 0; // Per-syscall manipulation. This code either succeeds, fakes timeout value and sets waitNsec, or returns false int timeoutArg = getTimeoutArg(syscall); if (syscall == SYS_futex) { // Check preconditions assert(timeoutArg == 3); int* uaddr = (int*) PIN_GetSyscallArgument(ctxt, std, 0); int op = (int) PIN_GetSyscallArgument(ctxt, std, 1); const struct timespec* timeout = (const struct timespec*) PIN_GetSyscallArgument(ctxt, std, 3); //info("FUTEX op %d waitOp %d uaddr %p ts %p", op, isFutexWaitOp(op), uaddr, timeout); if (!(uaddr && isFutexWaitOp(op) && timeout)) return false; // not a timeout FUTEX_WAIT waitNsec = timeout->tv_sec*1000000000L + timeout->tv_nsec; if (op | FUTEX_CLOCK_REALTIME) { // NOTE: FUTEX_CLOCK_REALTIME is not a documented interface AFAIK, but looking at the Linux source code + with some verification, this is the xlat uint32_t domain = zinfo->procArray[procIdx]->getClockDomain(); uint64_t simNs = cyclesToNs(zinfo->globPhaseCycles); uint64_t offsetNs = simNs + zinfo->clockDomainInfo[domain].realtimeOffsetNs; //info(" REALTIME FUTEX: %ld %ld %ld %ld", waitNsec, simNs, offsetNs, waitNsec-offsetNs); waitNsec = (waitNsec > (int64_t)offsetNs)? (waitNsec - offsetNs) : 0; } if (waitNsec <= 0) return false; // while technically waiting, this does not block. I'm guessing this is done for trylocks? It's weird. fakeTimeouts[tid].tv_sec = 0; fakeTimeouts[tid].tv_nsec = 20*1000*1000; // timeout every 20ms of actual host time PIN_SetSyscallArgument(ctxt, std, 3, (ADDRINT)&fakeTimeouts[tid]); } else { assert(syscall == SYS_epoll_wait || syscall == SYS_epoll_pwait || syscall == SYS_poll); int timeout = (int) PIN_GetSyscallArgument(ctxt, std, timeoutArg); if (timeout <= 0) return false; //info("[%d] pre-patch epoll_wait/pwait", tid); PIN_SetSyscallArgument(ctxt, std, timeoutArg, 20); // 20ms timeout waitNsec = ((uint64_t)timeout)*1000*1000; // timeout is in ms } //info("[%d] pre-patch %s (%d) waitNsec = %ld", tid, GetSyscallName(syscall), syscall, waitNsec); uint64_t waitCycles = waitNsec*zinfo->freqMHz/1000; uint64_t waitPhases = waitCycles/zinfo->phaseLength; if (waitPhases < 2) waitPhases = 2; // at least wait 2 phases; this should basically eliminate the chance that we get a SIGSYS before we start executing the syscal instruction uint64_t wakeupPhase = zinfo->numPhases + waitPhases; /*volatile uint32_t* futexWord =*/ zinfo->sched->markForSleep(procIdx, tid, wakeupPhase); // we still want to mark for sleep, bear with me... inFakeTimeoutMode[tid] = true; return true; }
/* Taint from Syscalls */ VOID Syscall_entry(THREADID thread_id, CONTEXT *ctx, SYSCALL_STANDARD std, void *v) { struct range taint; /* Taint from read */ if (PIN_GetSyscallNumber(ctx, std) == __NR_read){ TRICKS(); taint.start = static_cast<UINT64>((PIN_GetSyscallArgument(ctx, std, 1))); taint.end = taint.start + static_cast<UINT64>((PIN_GetSyscallArgument(ctx, std, 2))); bytesTainted.push_back(taint); std::cout << "[TAINT]\t\t\tbytes tainted from " << std::hex << "0x" << taint.start << " to 0x" << taint.end << " (via read)"<< std::endl; } }
PostPatchFn PatchTimeoutSyscall(PrePatchArgs args) { if (SkipTimeoutVirt(args)) return NullPostPatch; int syscall = PIN_GetSyscallNumber(args.ctxt, args.std); assert_msg(syscall == SYS_futex || syscall == SYS_epoll_wait || syscall == SYS_epoll_pwait || syscall == SYS_poll, "Invalid timeout syscall %d", syscall); FutexInfo fi = {0, 0}; if (syscall == SYS_futex) fi = PrePatchFutex(args.tid, args.ctxt, args.std); if (PrePatchTimeoutSyscall(args.tid, args.ctxt, args.std, syscall)) { ADDRINT prevIp = PIN_GetContextReg(args.ctxt, REG_INST_PTR); ADDRINT timeoutArgVal = PIN_GetSyscallArgument(args.ctxt, args.std, getTimeoutArg(syscall)); return [syscall, prevIp, timeoutArgVal, fi](PostPatchArgs args) { if (PostPatchTimeoutSyscall(args.tid, args.ctxt, args.std, syscall, prevIp, timeoutArgVal)) { return PPA_USE_NOP_PTRS; // retry } else { if (syscall == SYS_futex) PostPatchFutex(args.tid, fi, args.ctxt, args.std); return PPA_USE_JOIN_PTRS; // finish } }; } else { if (syscall == SYS_futex) { return [fi](PostPatchArgs args) { PostPatchFutex(args.tid, fi, args.ctxt, args.std); return PPA_NOTHING; }; } else { return NullPostPatch; } } }
VOID Syscall_entry(THREADID thread_id, CONTEXT *ctx, SYSCALL_STANDARD std, void *v) { unsigned int i; UINT64 start, size; if (PIN_GetSyscallNumber(ctx, std) == __NR_read){ TRICKS(); /* tricks to ignore the first open */ start = static_cast<UINT64>((PIN_GetSyscallArgument(ctx, std, 1))); size = static_cast<UINT64>((PIN_GetSyscallArgument(ctx, std, 2))); for (i = 0; i < size; i++) addressTainted.push_back(start+i); std::cout << "[TAINT]\t\t\tbytes tainted from " << std::hex << "0x" << start << " to 0x" << start+size << " (via read)"<< std::endl; } }
VOID SyscallEntry(THREADID threadIndex, CONTEXT *ctxt, SYSCALL_STANDARD std, VOID *v) { flush_mwrite(threadIndex); ADDRINT num = PIN_GetSyscallNumber(ctxt, std); if(num == SYS_execve) { PrintTime(NULL); output_dummy_stacktrace(); mprintf("mtrace_execve(%ld, %u, %u, %u, %u) = 0\n", syscall(SYS_gettid), PIN_GetTid(), getpid(), threadIndex, PIN_ThreadId()); m_dump_bytes(NULL, 0); return; } if (num != SYS_mmap && num != SYS_munmap) { thread_to_syscall[threadIndex].ip = 0; return; } thread_to_syscall[threadIndex].num = num; thread_to_syscall[threadIndex].ip = PIN_GetContextReg(ctxt, REG_INST_PTR); if(num == SYS_mmap) { for(int i = 0; i < 6; i++) { #if defined(TARGET_LINUX) && defined(TARGET_IA32) thread_to_syscall[threadIndex].args[i] = (reinterpret_cast<ADDRINT *>(PIN_GetSyscallArgument(ctxt, std, 0)))[i]; #else thread_to_syscall[threadIndex].args[i] = PIN_GetSyscallArgument(ctxt, std, i); #endif } } else { for(int i = 0; i < 2; i++) { thread_to_syscall[threadIndex].args[i] = PIN_GetSyscallArgument(ctxt, std, i); } } }
VOID SyscallEntry(THREADID threadIndex, CONTEXT *ctxt, SYSCALL_STANDARD std, VOID *v) { sysargs(PIN_GetSyscallNumber(ctxt, std), PIN_GetSyscallArgument(ctxt, std, 0), PIN_GetSyscallArgument(ctxt, std, 1), PIN_GetSyscallArgument(ctxt, std, 2), PIN_GetSyscallArgument(ctxt, std, 3), PIN_GetSyscallArgument(ctxt, std, 4), PIN_GetSyscallArgument(ctxt, std, 5)); }
VOID SyscallEntry(THREADID threadIndex, CONTEXT *ctxt, SYSCALL_STANDARD std, VOID *v) { SysBefore(PIN_GetContextReg(ctxt, REG_INST_PTR), PIN_GetSyscallNumber(ctxt, std), PIN_GetSyscallArgument(ctxt, std, 0), PIN_GetSyscallArgument(ctxt, std, 1), PIN_GetSyscallArgument(ctxt, std, 2), PIN_GetSyscallArgument(ctxt, std, 3), PIN_GetSyscallArgument(ctxt, std, 4), PIN_GetSyscallArgument(ctxt, std, 5)); }
static PyObject *Triton_getSyscallArgument(PyObject *self, PyObject *args) { PyObject *num; PyObject *std; uint64 ret; /* Extract arguments */ PyArg_ParseTuple(args, "O|O", &std, &num); if (!PyLong_Check(std) && !PyInt_Check(std)) return PyErr_Format(PyExc_TypeError, "getSyscallArgument(): expected an id (integer) as first argument"); if (!PyLong_Check(num) && !PyInt_Check(num)) return PyErr_Format(PyExc_TypeError, "getSyscallArgument(): expected an id (integer) as second argument"); LEVEL_CORE::SYSCALL_STANDARD standard = static_cast<LEVEL_CORE::SYSCALL_STANDARD>(PyLong_AsLong(std));; CONTEXT *ctx = static_cast<CONTEXT*>(ap.getCurrentCtxH()->getCtx()); ret = PIN_GetSyscallArgument(ctx, standard, PyLong_AsLong(num)); return PyLong_FromLong(ret); }
/* * syscall enter notification (analysis function) * * save the system call context and invoke the pre-syscall callback * function (if registered) * * @tid: thread id * @ctx: CPU context * @std: syscall standard (e.g., Linux IA-32, IA-64, etc) * @v: callback value */ static void sysenter_save(THREADID tid, CONTEXT *ctx, SYSCALL_STANDARD std, VOID *v) { /* get the thread context */ thread_ctx_t *thread_ctx = (thread_ctx_t *) PIN_GetContextReg(ctx, thread_ctx_ptr); /* get the syscall number */ size_t syscall_nr = PIN_GetSyscallNumber(ctx, std); /* unknown syscall; optimized branch */ if (unlikely(syscall_nr >= SYSCALL_MAX)) { //LOG(string(__FUNCTION__) + ": unknown syscall (num=" + // decstr(syscall_nr) + ")\n"); /* syscall number is set to -1; hint for the sysexit_save() */ thread_ctx->syscall_ctx.nr = -1; /* no context save and no pre-syscall callback invocation */ return; } /* pass the system call number to sysexit_save() */ thread_ctx->syscall_ctx.nr = syscall_nr; /* * check if we need to save the arguments for that syscall * * we save only when we have a callback registered or the syscall * returns a value in the arguments */ if (syscall_desc[syscall_nr].save_args | syscall_desc[syscall_nr].retval_args) { /* * dump only the appropriate number of arguments * or yet another lame way to avoid a loop (vpk) */ switch (syscall_desc[syscall_nr].nargs) { /* 6 */ case SYSCALL_ARG5 + 1: thread_ctx->syscall_ctx.arg[SYSCALL_ARG5] = PIN_GetSyscallArgument(ctx, std, SYSCALL_ARG5); /* 5 */ case SYSCALL_ARG4 + 1: thread_ctx->syscall_ctx.arg[SYSCALL_ARG4] = PIN_GetSyscallArgument(ctx, std, SYSCALL_ARG4); /* 4 */ case SYSCALL_ARG3 + 1: thread_ctx->syscall_ctx.arg[SYSCALL_ARG3] = PIN_GetSyscallArgument(ctx, std, SYSCALL_ARG3); /* 3 */ case SYSCALL_ARG2 + 1: thread_ctx->syscall_ctx.arg[SYSCALL_ARG2] = PIN_GetSyscallArgument(ctx, std, SYSCALL_ARG2); /* 2 */ case SYSCALL_ARG1 + 1: thread_ctx->syscall_ctx.arg[SYSCALL_ARG1] = PIN_GetSyscallArgument(ctx, std, SYSCALL_ARG1); /* 1 */ case SYSCALL_ARG0 + 1: thread_ctx->syscall_ctx.arg[SYSCALL_ARG0] = PIN_GetSyscallArgument(ctx, std, SYSCALL_ARG0); /* default */ default: /* nothing to do */ break; } /* * dump the architectural state of the processor; * saved as "auxiliary" data */ thread_ctx->syscall_ctx.aux = ctx; /* call the pre-syscall callback (if any) */ if (syscall_desc[syscall_nr].pre != NULL) syscall_desc[syscall_nr].pre(&thread_ctx->syscall_ctx); } }
/* ========================================================================== */ VOID SyscallEntry(THREADID threadIndex, CONTEXT* ictxt, SYSCALL_STANDARD std, VOID* v) { /* Kill speculative feeder before reaching a syscall. * This guarantees speculative processes don't have side effects. */ if (speculation_mode) { FinishSpeculation(get_tls(threadIndex)); return; } lk_lock(&syscall_lock, threadIndex + 1); ADDRINT syscall_num = PIN_GetSyscallNumber(ictxt, std); ADDRINT arg1 = PIN_GetSyscallArgument(ictxt, std, 0); ADDRINT arg2; ADDRINT arg3; mmap_arg_struct mmap_arg; thread_state_t* tstate = get_tls(threadIndex); tstate->last_syscall_number = syscall_num; #ifdef SYSCALL_DEBUG stringstream log; log << tstate->tid << ": "; #endif switch (syscall_num) { case __NR_brk: #ifdef SYSCALL_DEBUG log << "Syscall brk(" << dec << syscall_num << ") addr: 0x" << hex << arg1 << dec << endl; #endif tstate->last_syscall_arg1 = arg1; break; case __NR_munmap: arg2 = PIN_GetSyscallArgument(ictxt, std, 1); #ifdef SYSCALL_DEBUG log << "Syscall munmap(" << dec << syscall_num << ") addr: 0x" << hex << arg1 << " length: " << arg2 << dec << endl; #endif tstate->last_syscall_arg1 = arg1; tstate->last_syscall_arg2 = arg2; break; case __NR_mmap: // oldmmap #ifndef _LP64 memcpy(&mmap_arg, (void*)arg1, sizeof(mmap_arg_struct)); #else mmap_arg.addr = arg1; mmap_arg.len = PIN_GetSyscallArgument(ictxt, std, 1); #endif tstate->last_syscall_arg1 = mmap_arg.len; #ifdef SYSCALL_DEBUG log << "Syscall oldmmap(" << dec << syscall_num << ") addr: 0x" << hex << mmap_arg.addr << " length: " << mmap_arg.len << dec << endl; #endif break; #ifndef _LP64 case __NR_mmap2: // ia32-only arg2 = PIN_GetSyscallArgument(ictxt, std, 1); #ifdef SYSCALL_DEBUG log << "Syscall mmap2(" << dec << syscall_num << ") addr: 0x" << hex << arg1 << " length: " << arg2 << dec << endl; #endif tstate->last_syscall_arg1 = arg2; break; #endif // _LP64 case __NR_mremap: arg2 = PIN_GetSyscallArgument(ictxt, std, 1); arg3 = PIN_GetSyscallArgument(ictxt, std, 2); #ifdef SYSCALL_DEBUG log << "Syscall mremap(" << dec << syscall_num << ") old_addr: 0x" << hex << arg1 << " old_length: " << arg2 << " new_length: " << arg3 << dec << endl; #endif tstate->last_syscall_arg1 = arg1; tstate->last_syscall_arg2 = arg2; tstate->last_syscall_arg3 = arg3; break; case __NR_gettimeofday: #ifdef SYSCALL_DEBUG log << "Syscall gettimeofday(" << dec << syscall_num << ")" << endl; #endif tstate->last_syscall_arg1 = arg1; BeforeGettimeofday(threadIndex, arg1); break; case __NR_mprotect: arg2 = PIN_GetSyscallArgument(ictxt, std, 1); arg3 = PIN_GetSyscallArgument(ictxt, std, 2); #ifdef SYSCALL_DEBUG log << "Syscall mprotect(" << dec << syscall_num << ") addr: " << hex << arg1 << dec << " length: " << arg2 << " prot: " << hex << arg3 << dec << endl; #endif tstate->last_syscall_arg1 = arg1; tstate->last_syscall_arg2 = arg2; tstate->last_syscall_arg3 = arg3; break; case __NR_futex: { { std::lock_guard<XIOSIM_LOCK> l(tstate->lock); if (tstate->ignore) break; } arg2 = PIN_GetSyscallArgument(ictxt, std, 1); tstate->last_syscall_arg1 = arg1; tstate->last_syscall_arg2 = arg2; #ifdef SYSCALL_DEBUG log << "Syscall futex(" << hex << arg1 << dec << ", " << arg2 << ")" << endl; #endif int futex_op = FUTEX_CMD_MASK & arg2; if (futex_op == FUTEX_WAIT || futex_op == FUTEX_WAIT_BITSET) { AddGiveUpHandshake(threadIndex, false, true); } } break; case __NR_epoll_wait: case __NR_epoll_pwait: #ifdef SYSCALL_DEBUG log << "Syscall epoll_wait(*)" << endl; #endif AddGiveUpHandshake(threadIndex, false, true); break; case __NR_poll: case __NR_ppoll: #ifdef SYSCALL_DEBUG log << "Syscall poll(*)" << endl; #endif AddGiveUpHandshake(threadIndex, false, true); break; case __NR_select: case __NR_pselect6: #ifdef SYSCALL_DEBUG log << "Syscall select(*)" << endl; #endif AddGiveUpHandshake(threadIndex, false, true); break; case __NR_nanosleep: #ifdef SYSCALL_DEBUG log << "Syscall nanosleep(*)" << endl; #endif AddGiveUpHandshake(threadIndex, false, true); break; case __NR_pause: #ifdef SYSCALL_DEBUG log << "Syscall pause(*)" << endl; #endif AddGiveUpHandshake(threadIndex, false, true); break; #ifdef SYSCALL_DEBUG case __NR_open: log << "Syscall open (" << dec << syscall_num << ") path: " << (char*)arg1 << endl; break; #endif #ifdef SYSCALL_DEBUG case __NR_exit: log << "Syscall exit (" << dec << syscall_num << ") code: " << arg1 << endl; break; #endif case __NR_sched_setaffinity: { arg2 = PIN_GetSyscallArgument(ictxt, std, 1); arg3 = PIN_GetSyscallArgument(ictxt, std, 2); #ifdef SYSCALL_DEBUG log << "Syscall sched_setaffinity(" << arg1 << ", " << arg2 << ")"; #endif size_t mask_size = (size_t) arg2; cpu_set_t* mask = (cpu_set_t*) arg3; if (CPU_COUNT(mask) > 1) { #ifdef SYSCALL_DEBUG log << endl; #endif cerr << "We don't virtualize sched_setaffinity with a mask > 1." << endl; break; } int coreID = xiosim::INVALID_CORE; for (size_t i = 0; i < mask_size; i++) { if (CPU_ISSET(i, mask)) { coreID = static_cast<int>(i); break; } } #ifdef SYSCALL_DEBUG log << " cpu " << coreID << endl; #endif AddAffinityHandshake(threadIndex, coreID); } break; /* case __NR_sysconf: #ifdef SYSCALL_DEBUG log << "Syscall sysconf (" << dec << syscall_num << ") arg: " << arg1 << endl; #endif tstate->last_syscall_arg1 = arg1; break; */ default: #ifdef SYSCALL_DEBUG log << "Syscall " << dec << syscall_num << endl; #endif break; } #ifdef SYSCALL_DEBUG cerr << log.str(); #endif lk_unlock(&syscall_lock); }