diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2022-09-04 15:21:32 +0200 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2022-09-04 15:21:32 +0200 |
| commit | a3f63a12f9102794ce1d94c972064f10a25e944b (patch) | |
| tree | 03d227251c87b5edd9019a616783e27f21587c88 /src | |
| parent | b2dfe64ceaeffcec02c98f5c332f8f8e31180dbd (diff) | |
| download | box64-a3f63a12f9102794ce1d94c972064f10a25e944b.tar.gz box64-a3f63a12f9102794ce1d94c972064f10a25e944b.zip | |
[DYNAREC] Improve memory protection tracking (help #361)
Diffstat (limited to 'src')
| -rw-r--r-- | src/custommem.c | 48 | ||||
| -rw-r--r-- | src/include/custommem.h | 5 | ||||
| -rwxr-xr-x | src/libtools/signals.c | 2 | ||||
| -rwxr-xr-x | src/tools/bridge.c | 12 |
4 files changed, 35 insertions, 32 deletions
diff --git a/src/custommem.c b/src/custommem.c index 83e4e1ec..0137084e 100644 --- a/src/custommem.c +++ b/src/custommem.c @@ -59,7 +59,8 @@ static pthread_mutex_t mutex_prot; #define MEMPROT_SHIFT2 (16+12) #endif #define MEMPROT_SIZE (1<<16) -static uint8_t *volatile memprot[1<<20]; // x86_64 mem is 48bits, page is 12bits, so memory is tracked as [20][16][page protection] +#define MEMPROT_SIZE0 (48-MEMPROT_SHIFT2) +static uint8_t *volatile memprot[1<<MEMPROT_SIZE0]; // x86_64 mem is 48bits, page is 12bits, so memory is tracked as [20][16][page protection] static uint8_t memprot_default[MEMPROT_SIZE]; static int inited = 0; @@ -708,34 +709,30 @@ void setJumpTableDefault64(void* addr) { uintptr_t idx3, idx2, idx1, idx0; idx3 = (((uintptr_t)addr)>>48)&0xffff; - idx2 = (((uintptr_t)addr)>>32)&0xffff; - idx1 = (((uintptr_t)addr)>>16)&0xffff; - idx0 = (((uintptr_t)addr) )&0xffff; if(box64_jmptbl3[idx3] == box64_jmptbldefault2) return; + idx2 = (((uintptr_t)addr)>>32)&0xffff; if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1) return; + idx1 = (((uintptr_t)addr)>>16)&0xffff; if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0) return; - if(box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)native_next) - return; + idx0 = (((uintptr_t)addr) )&0xffff; box64_jmptbl3[idx3][idx2][idx1][idx0] = (uintptr_t)native_next; } int isJumpTableDefault64(void* addr) { uintptr_t idx3, idx2, idx1, idx0; idx3 = (((uintptr_t)addr)>>48)&0xffff; - idx2 = (((uintptr_t)addr)>>32)&0xffff; - idx1 = (((uintptr_t)addr)>>16)&0xffff; - idx0 = (((uintptr_t)addr) )&0xffff; if(box64_jmptbl3[idx3] == box64_jmptbldefault2) return 1; + idx2 = (((uintptr_t)addr)>>32)&0xffff; if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1) return 1; + idx1 = (((uintptr_t)addr)>>16)&0xffff; if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0) return 1; - if(box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)native_next) - return 1; + idx0 = (((uintptr_t)addr) )&0xffff; return (box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)native_next)?1:0; } uintptr_t getJumpTable64() @@ -800,19 +797,20 @@ void protectDB(uintptr_t addr, uintptr_t size) if(!prot) prot = PROT_READ | PROT_WRITE | PROT_EXEC; // comes from malloc & co, so should not be able to execute if((prot&PROT_WRITE)) { - prot&=~PROT_WRITE; + prot&=~(PROT_WRITE | PROT_CUSTOM); mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot); memprot[i>>16][i&0xffff] = prot|PROT_DYNAREC; // need to use atomic exchange? - } + } else + memprot[i>>16][i&0xffff] = prot|PROT_DYNAREC_R; } pthread_mutex_unlock(&mutex_prot); } // Add the Write flag from an adress range, and mark all block as dirty // no log, as it can be executed inside a signal handler -void unprotectDB(uintptr_t addr, size_t size) +void unprotectDB(uintptr_t addr, size_t size, int mark) { - dynarec_log(LOG_DEBUG, "unprotectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1)); + dynarec_log(LOG_DEBUG, "unprotectDB %p -> %p (mark=%d)\n", (void*)addr, (void*)(addr+size-1), mark); uintptr_t idx = (addr>>MEMPROT_SHIFT); uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT); if(end>=(1LL<<(48-MEMPROT_SHIFT))) @@ -831,12 +829,14 @@ void unprotectDB(uintptr_t addr, size_t size) for (uintptr_t i=idx; i<=end; ++i) { uint32_t prot = memprot[i>>16][i&0xffff]; if(prot&PROT_DYNAREC) { - prot&=~PROT_DYNAREC; + prot&=~PROT_CUSTOM; prot|=PROT_WRITE; - cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0); + if(mark) + cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0); mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot); memprot[i>>16][i&0xffff] = prot; // need to use atomic exchange? - } + } else if(prot&PROT_DYNAREC_R) + memprot[i>>16][i&0xffff] = prot&~PROT_CUSTOM; } pthread_mutex_unlock(&mutex_prot); } @@ -854,7 +854,7 @@ int isprotectedDB(uintptr_t addr, size_t size) } for (uintptr_t i=idx; i<=end; ++i) { uint32_t prot = memprot[i>>16][i&0xffff]; - if((prot&PROT_WRITE)) { + if(!(prot&PROT_DYNAREC || prot&PROT_DYNAREC_R)) { dynarec_log(LOG_DEBUG, "0\n"); return 0; } @@ -978,9 +978,11 @@ void updateProtection(uintptr_t addr, size_t size, uint32_t prot) #endif } for (uintptr_t i=idx; i<=end; ++i) { - uint32_t dyn=(memprot[i>>16][i&0xffff]&PROT_DYNAREC); - if(dyn && (prot&PROT_WRITE)) // need to remove the write protection from this block + uint32_t dyn=(memprot[i>>16][i&0xffff]&(PROT_DYNAREC | PROT_DYNAREC_R)); + if(dyn && (prot&PROT_WRITE)) { // need to remove the write protection from this block + dyn = PROT_DYNAREC; mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE); + } memprot[i>>16][i&0xffff] = prot|dyn; } pthread_mutex_unlock(&mutex_prot); @@ -1232,7 +1234,7 @@ void init_custommem_helper(box64context_t* ctx) return; inited = 1; memset(memprot_default, 0, sizeof(memprot_default)); - for(int i=0; i<(1<<20); ++i) + for(int i=0; i<(1<<MEMPROT_SIZE0); ++i) memprot[i] = memprot_default; init_mutexes(); #ifdef DYNAREC @@ -1320,7 +1322,7 @@ void fini_custommem_helper(box64context_t *ctx) lockaddress = NULL; #endif uint8_t* m; - for(int i=0; i<(1<<20); ++i) { + for(int i=0; i<(1<<MEMPROT_SIZE0); ++i) { m = memprot[i]; if(m!=memprot_default) box_free(m); diff --git a/src/include/custommem.h b/src/include/custommem.h index dba8b1f8..c8a28fc5 100644 --- a/src/include/custommem.h +++ b/src/include/custommem.h @@ -35,7 +35,8 @@ uintptr_t getJumpTableAddress64(uintptr_t addr); #endif #define PROT_DYNAREC 0x80 -#define PROT_CUSTOM (PROT_DYNAREC) +#define PROT_DYNAREC_R 0x40 +#define PROT_CUSTOM (PROT_DYNAREC | PROT_DYNAREC_R) void updateProtection(uintptr_t addr, size_t size, uint32_t prot); void setProtection(uintptr_t addr, size_t size, uint32_t prot); @@ -44,7 +45,7 @@ uint32_t getProtection(uintptr_t addr); void loadProtectionFromMap(); #ifdef DYNAREC void protectDB(uintptr_t addr, size_t size); -void unprotectDB(uintptr_t addr, size_t size); +void unprotectDB(uintptr_t addr, size_t size, int mark); // if mark==0, the blocks are not marked as potentially dirty int isprotectedDB(uintptr_t addr, size_t size); #endif void* find32bitBlock(size_t size); diff --git a/src/libtools/signals.c b/src/libtools/signals.c index c003c863..df0b7d0b 100755 --- a/src/libtools/signals.c +++ b/src/libtools/signals.c @@ -808,7 +808,7 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx) repeated_count = 0; } // access error, unprotect the block (and mark them dirty) - unprotectDB((uintptr_t)addr, 1); // unprotect 1 byte... But then, the whole page will be unprotected + unprotectDB((uintptr_t)addr, 1, 1); // unprotect 1 byte... But then, the whole page will be unprotected if(db && ((addr>=db->x64_addr && addr<(db->x64_addr+db->x64_size)) || db->need_test)) { // dynablock got auto-dirty! need to get out of it!!! emu_jmpbuf_t* ejb = GetJmpBuf(); diff --git a/src/tools/bridge.c b/src/tools/bridge.c index 8f9c7dad..8c9070eb 100755 --- a/src/tools/bridge.c +++ b/src/tools/bridge.c @@ -68,8 +68,8 @@ void FreeBridge(bridge_t** bridge) while(b) { brick_t *n = b->next; #ifdef DYNAREC - if(getProtection((uintptr_t)b->b)&PROT_DYNAREC) - unprotectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t)); + if(getProtection((uintptr_t)b->b)&(PROT_DYNAREC|PROT_DYNAREC_R)) + unprotectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t), 1); #endif my_munmap(emu, b->b, NBRICK*sizeof(onebridge_t)); box_free(b); @@ -103,9 +103,9 @@ uintptr_t AddBridge(bridge_t* bridge, wrapper_t w, void* fnc, int N, const char* #ifdef DYNAREC pthread_mutex_unlock(&my_context->mutex_bridge); if(box64_dynarec) { - prot=(getProtection((uintptr_t)b->b)&PROT_DYNAREC)?1:0; + prot=(getProtection((uintptr_t)b->b)&(PROT_DYNAREC|PROT_DYNAREC_R))?1:0; if(prot) - unprotectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t)); + unprotectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t), 0); else // only add DB if there is no protection addDBFromAddressRange((uintptr_t)&b->b[b->sz].CC, sizeof(onebridge_t)); } @@ -234,9 +234,9 @@ uintptr_t AddVSyscall(bridge_t* bridge, int num) #ifdef DYNAREC pthread_mutex_unlock(&my_context->mutex_bridge); if(box64_dynarec) { - prot=(getProtection((uintptr_t)b->b)&PROT_DYNAREC)?1:0; + prot=(getProtection((uintptr_t)b->b)&(PROT_DYNAREC|PROT_DYNAREC_R))?1:0; if(prot) - unprotectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t)); + unprotectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t), 0); else // only add DB if there is no protection addDBFromAddressRange((uintptr_t)&b->b[b->sz].CC, sizeof(onebridge_t)); } |