diff options
Diffstat (limited to 'src/libtools/signals.c')
| -rw-r--r-- | src/libtools/signals.c | 93 |
1 files changed, 71 insertions, 22 deletions
diff --git a/src/libtools/signals.c b/src/libtools/signals.c index e7280663..eebae427 100644 --- a/src/libtools/signals.c +++ b/src/libtools/signals.c @@ -286,7 +286,7 @@ static __thread int signal_jmpbuf_active = 0; //1<<1 is mutex_prot, 1<<8 is mutex_dyndump #define is_memprot_locked (1<<1) #define is_dyndump_locked (1<<8) -uint64_t RunFunctionHandler(int* exit, int dynarec, x64_ucontext_t* sigcontext, uintptr_t fnc, int nargs, ...) +uint64_t RunFunctionHandler(x64emu_t* emu, int* exit, int dynarec, x64_ucontext_t* sigcontext, uintptr_t fnc, int nargs, ...) { if(fnc==0 || fnc==1) { va_list va; @@ -311,8 +311,8 @@ uint64_t RunFunctionHandler(int* exit, int dynarec, x64_ucontext_t* sigcontext, // Dynarec cannot be used in signal handling unless custom malloc is used dynarec = 0; #endif - - x64emu_t *emu = thread_get_emu(); + if(!emu) + emu = thread_get_emu(); #ifdef DYNAREC if(box64_dynarec_test) emu->test.test = 0; @@ -927,7 +927,7 @@ int sigbus_specialcases(siginfo_t* info, void * ucntx, void* pc, void* _fpsimd) #ifdef BOX32 void my_sigactionhandler_oldcode_32(int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db); #endif -void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db) +void my_sigactionhandler_oldcode(x64emu_t* emu, int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db) { #ifdef BOX32 if(box64_is32bits) { @@ -936,12 +936,14 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void } #endif int Locks = unlockMutex(); + int log_minimum = (box64_showsegv)?LOG_NONE:((sig==SIGSEGV && my_context->is_sigaction[sig])?LOG_DEBUG:LOG_INFO); printf_log(LOG_DEBUG, "Sigactionhanlder for signal #%d called (jump to %p/%s)\n", sig, (void*)my_context->signals[sig], GetNativeName((void*)my_context->signals[sig])); uintptr_t restorer = my_context->restorer[sig]; // get that actual ESP first! - x64emu_t *emu = thread_get_emu(); + if(!emu) + emu = thread_get_emu(); uintptr_t frame = R_RSP; #if defined(DYNAREC) #if defined(ARM64) @@ -1143,22 +1145,42 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void TRAP_x86_CACHEFLT = 19 // SIMD exception (via SIGFPE) if CPU is SSE capable otherwise Cache flush exception (via SIGSEV) */ uint32_t prot = getProtection((uintptr_t)info->si_addr); + uint32_t real_prot = 0; + if(prot&PROT_READ) real_prot|=PROT_READ; + if(prot&PROT_WRITE) real_prot|=PROT_WRITE; + if(prot&PROT_EXEC) real_prot|=PROT_WRITE; + if(prot&PROT_DYNAREC) real_prot|=PROT_WRITE; + sigcontext->uc_mcontext.gregs[X64_ERR] = 0; + sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 0; if(sig==SIGBUS) sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 17; else if(sig==SIGSEGV) { if((uintptr_t)info->si_addr == sigcontext->uc_mcontext.gregs[X64_RIP]) { - sigcontext->uc_mcontext.gregs[X64_ERR] = (info->si_errno==0x1234)?0:((info->si_errno==0xdead)?(0x2|(info->si_code<<3)):0x0010); // execution flag issue (probably), unless it's a #GP(0) - sigcontext->uc_mcontext.gregs[X64_TRAPNO] = ((info->si_code==SEGV_ACCERR) || (info->si_errno==0x1234) || (info->si_errno==0xdead) || ((uintptr_t)info->si_addr==0))?13:14; + if(info->si_errno==0xbad0) { + //bad opcode + sigcontext->uc_mcontext.gregs[X64_ERR] = 0; + sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 13; + info2->si_errno = 0; + } else if (info->si_errno==0xecec) { + // no excute bit on segment + sigcontext->uc_mcontext.gregs[X64_ERR] = (real_prot&PROT_READ)?16:1; // EXECUTE_FAULT & READ_FAULT + sigcontext->uc_mcontext.gregs[X64_TRAPNO] = (getMmapped((uintptr_t)info->si_addr))?14:13; + info2->si_errno = 0; + }else { + sigcontext->uc_mcontext.gregs[X64_ERR] = (real_prot&PROT_READ)?16:1;//(info->si_errno==0x1234)?0:((info->si_errno==0xdead)?(0x2|(info->si_code<<3)):0x0010); // execution flag issue (probably), unless it's a #GP(0) + sigcontext->uc_mcontext.gregs[X64_TRAPNO] = (getMmapped((uintptr_t)info->si_addr))?14:13; + //sigcontext->uc_mcontext.gregs[X64_TRAPNO] = ((info->si_code==SEGV_ACCERR) || (info->si_errno==0x1234) || (info->si_errno==0xdead) || ((uintptr_t)info->si_addr==0))?13:14; + } } else if(info->si_code==SEGV_ACCERR && !(prot&PROT_WRITE)) { - sigcontext->uc_mcontext.gregs[X64_ERR] = 0x0002; // write flag issue + sigcontext->uc_mcontext.gregs[X64_ERR] = (real_prot&PROT_READ)?2:1;//0x0002; // write flag issue sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 14; } else { if((info->si_code!=SEGV_ACCERR) && labs((intptr_t)info->si_addr-(intptr_t)sigcontext->uc_mcontext.gregs[X64_RSP])<16) sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 12; // stack overflow probably else - sigcontext->uc_mcontext.gregs[X64_TRAPNO] = (info->si_code == SEGV_ACCERR)?13:14; + sigcontext->uc_mcontext.gregs[X64_TRAPNO] = (info->si_code == SEGV_ACCERR)?14:13; //X64_ERR seems to be INT:8 CODE:8. So for write access segfault it's 0x0002 For a read it's 0x0004 (and 8 for exec). For an int 2d it could be 0x2D01 for example - sigcontext->uc_mcontext.gregs[X64_ERR] = 0x0004; // read error? there is no execute control in box64 anyway + sigcontext->uc_mcontext.gregs[X64_ERR] = 0x0001; // read error? } if(info->si_code == SEGV_ACCERR && old_code) *old_code = -1; @@ -1166,7 +1188,7 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void info2->si_errno = 0; } else if(info->si_errno==0xdead) { // INT x - uint8_t int_n = info2->si_code; + uint8_t int_n = info->si_code; info2->si_errno = 0; info2->si_code = info->si_code; info2->si_addr = NULL; @@ -1201,7 +1223,7 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void sigcontext->uc_mcontext.gregs[X64_ERR] = 0; } //TODO: SIGABRT generate what? - printf_log(LOG_DEBUG, "Signal %d: si_addr=%p, TRAPNO=%d, ERR=%d, RIP=%p\n", sig, (void*)info2->si_addr, sigcontext->uc_mcontext.gregs[X64_TRAPNO], sigcontext->uc_mcontext.gregs[X64_ERR],sigcontext->uc_mcontext.gregs[X64_RIP]); + printf_log((sig==10)?LOG_DEBUG:log_minimum, "Signal %d: si_addr=%p, TRAPNO=%d, ERR=%d, RIP=%p\n", sig, (void*)info2->si_addr, sigcontext->uc_mcontext.gregs[X64_TRAPNO], sigcontext->uc_mcontext.gregs[X64_ERR],sigcontext->uc_mcontext.gregs[X64_RIP]); // call the signal handler x64_ucontext_t sigcontext_copy = *sigcontext; // save old value from emu @@ -1227,7 +1249,7 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void if(sig!=SIGSEGV && !(Locks&is_dyndump_locked) && !(Locks&is_memprot_locked)) dynarec = 1; #endif - ret = RunFunctionHandler(&exits, dynarec, sigcontext, my_context->signals[info2->si_signo], 3, info2->si_signo, info2, sigcontext); + ret = RunFunctionHandler(emu, &exits, dynarec, sigcontext, my_context->signals[info2->si_signo], 3, info2->si_signo, info2, sigcontext); // restore old value from emu if(used_stack) // release stack new_ss->ss_flags = 0; @@ -1279,7 +1301,7 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void #undef GO for(int i=0; i<6; ++i) emu->segs_serial[i] = 0; - printf_log(LOG_DEBUG, "Context has been changed in Sigactionhanlder, doing siglongjmp to resume emu at %p, RSP=%p\n", (void*)R_RIP, (void*)R_RSP); + printf_log((sig==10)?LOG_DEBUG:log_minimum, "Context has been changed in Sigactionhanlder, doing siglongjmp to resume emu at %p, RSP=%p\n", (void*)R_RIP, (void*)R_RSP); if(old_code) *old_code = -1; // re-init the value to allow another segfault at the same place //relockMutex(Locks); // do not relock mutex, because of the siglongjmp, whatever was running is canceled @@ -1339,7 +1361,7 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void exit(ret); } if(restorer) - RunFunctionHandler(&exits, 0, NULL, restorer, 0); + RunFunctionHandler(emu, &exits, 0, NULL, restorer, 0); relockMutex(Locks); } @@ -1854,7 +1876,7 @@ dynarec_log(/*LOG_DEBUG*/LOG_INFO, "Repeated SIGSEGV with Access error on %p for } relockMutex(Locks); if(my_context->signals[sig] && my_context->signals[sig]!=1) { - my_sigactionhandler_oldcode(sig, my_context->is_sigaction[sig]?0:1, info, ucntx, &old_code, db); + my_sigactionhandler_oldcode(emu, sig, my_context->is_sigaction[sig]?0:1, info, ucntx, &old_code, db); return; } // no handler (or double identical segfault) @@ -1882,7 +1904,7 @@ void my_sigactionhandler(int32_t sig, siginfo_t* info, void * ucntx) void* db = NULL; #endif - my_sigactionhandler_oldcode(sig, 0, info, ucntx, NULL, db); + my_sigactionhandler_oldcode(NULL, sig, 0, info, ucntx, NULL, db); } #ifndef DYNAREC @@ -1895,6 +1917,13 @@ void emit_signal(x64emu_t* emu, int sig, void* addr, int code) info.si_signo = sig; info.si_errno = (sig==SIGSEGV)?0x1234:0; // Mark as a sign this is a #GP(0) (like privileged instruction) info.si_code = code; + if(sig==SIGSEGV && code==0xbad0) { + info.si_errno = 0xbad0; + info.si_code = 0; + } else if(sig==SIGSEGV && code==0xecec) { + info.si_errno = 0xecec; + info.si_code = SEGV_ACCERR; + } info.si_addr = addr; const char* x64name = NULL; const char* elfname = NULL; @@ -1903,13 +1932,33 @@ void emit_signal(x64emu_t* emu, int sig, void* addr, int code) elfheader_t* elf = FindElfAddress(my_context, R_RIP); if(elf) elfname = ElfName(elf); - printf_log(LOG_NONE, "Emit Signal %d at IP=%p(%s / %s) / addr=%p, code=%d\n", sig, (void*)R_RIP, x64name?x64name:"???", elfname?elfname:"?", addr, code); + printf_log(LOG_NONE, "Emit Signal %d at IP=%p(%s / %s) / addr=%p, code=0x%x\n", sig, (void*)R_RIP, x64name?x64name:"???", elfname?elfname:"?", addr, code); +printf_log(LOG_NONE, DumpCPURegs(emu, R_RIP, emu->segs[_CS]==0x23)); + //if(!elf) { + // FILE* f = fopen("/proc/self/maps", "r"); + // if(f) { + // char line[1024]; + // while(!feof(f)) { + // char* ret = fgets(line, sizeof(line), f); + // printf_log(LOG_NONE, "\t%s", ret); + // } + // fclose(f); + // } + //} if(sig==SIGILL) { uint8_t* mem = (uint8_t*)R_RIP; printf_log(LOG_NONE, "SIGILL: Opcode at ip is %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n", mem[0], mem[1], mem[2], mem[3], mem[4], mem[5]); } } - my_sigactionhandler_oldcode(sig, 0, &info, NULL, NULL, NULL); + my_sigactionhandler_oldcode(emu, sig, 0, &info, NULL, NULL, NULL); +} + +void check_exec(x64emu_t* emu, uintptr_t addr) +{ + while((getProtection(addr)&(PROT_EXEC|PROT_READ))!=(PROT_EXEC|PROT_READ)) { + R_RIP = addr; // incase there is a slight difference + emit_signal(emu, SIGSEGV, (void*)addr, 0xecec); + } } void emit_interruption(x64emu_t* emu, int num, void* addr) @@ -1918,7 +1967,7 @@ void emit_interruption(x64emu_t* emu, int num, void* addr) info.si_signo = SIGSEGV; info.si_errno = 0xdead; info.si_code = num; - info.si_addr = addr; + info.si_addr = NULL;//addr; const char* x64name = NULL; const char* elfname = NULL; if(box64_log>LOG_INFO || box64_dynarec_dump || box64_showsegv) { @@ -1928,7 +1977,7 @@ void emit_interruption(x64emu_t* emu, int num, void* addr) elfname = ElfName(elf); printf_log(LOG_NONE, "Emit Interruption 0x%x at IP=%p(%s / %s) / addr=%p\n", num, (void*)R_RIP, x64name?x64name:"???", elfname?elfname:"?", addr); } - my_sigactionhandler_oldcode(SIGSEGV, 0, &info, NULL, NULL, NULL); + my_sigactionhandler_oldcode(emu, SIGSEGV, 0, &info, NULL, NULL, NULL); } void emit_div0(x64emu_t* emu, void* addr, int code) @@ -1947,7 +1996,7 @@ void emit_div0(x64emu_t* emu, void* addr, int code) elfname = ElfName(elf); printf_log(LOG_NONE, "Emit Divide by 0 at IP=%p(%s / %s) / addr=%p\n", (void*)R_RIP, x64name?x64name:"???", elfname?elfname:"?", addr); } - my_sigactionhandler_oldcode(SIGSEGV, 0, &info, NULL, NULL, NULL); + my_sigactionhandler_oldcode(emu, SIGSEGV, 0, &info, NULL, NULL, NULL); } EXPORT sighandler_t my_signal(x64emu_t* emu, int signum, sighandler_t handler) |