about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2022-09-04 15:21:32 +0200
committerptitSeb <sebastien.chev@gmail.com>2022-09-04 15:21:32 +0200
commita3f63a12f9102794ce1d94c972064f10a25e944b (patch)
tree03d227251c87b5edd9019a616783e27f21587c88 /src
parentb2dfe64ceaeffcec02c98f5c332f8f8e31180dbd (diff)
downloadbox64-a3f63a12f9102794ce1d94c972064f10a25e944b.tar.gz
box64-a3f63a12f9102794ce1d94c972064f10a25e944b.zip
[DYNAREC] Improve memory protection tracking (help #361)
Diffstat (limited to 'src')
-rw-r--r--src/custommem.c48
-rw-r--r--src/include/custommem.h5
-rwxr-xr-xsrc/libtools/signals.c2
-rwxr-xr-xsrc/tools/bridge.c12
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));
         }