Skip to content

[NON4KPAGE] desired memory protection of the mapping for pages need writable #3256

@xiangzhai

Description

@xiangzhai

Hi,

Testcase reproduced failed to STORE to base address 0x40002f94 enabled BOX32:

cmake .. -DLARCH64=ON -DLARCH64_ABI_1=ON -DBOX32=ON
...
gdb -ex=r --args ./box64 ../tests32/test14
...
[BOX64] Running on Loongson-3A5000-HV with 4 cores, pagesize: 16384
...
Program received signal SIGSEGV, Segmentation fault.
0x0000000100211cf8 in ?? ()
...
=> 0x100211cf8:	st.w	$r4,$r10,252(0xfc)
...
(gdb) i r $r10
r10            0x40002f94          1073754004

The root cause is 0x40000000 ~ 0x40004000 is not writable:

30000000-30004000 rwxp 00000000 00:00 0 
30010000-30810000 rw-p 00000000 00:00 0 
30810000-30824000 rwxp 00000000 00:00 0 
34800000-35d1c000 r-xp 00000000 08:07 3292162                            /home/zhaixiang/repo/box64/build/box64
35d1c000-35d20000 r-xp 01518000 08:07 3292162                            /home/zhaixiang/repo/box64/build/box64
35d20000-35d28000 rwxp 0151c000 08:07 3292162                            /home/zhaixiang/repo/box64/build/box64
35d28000-36cf4000 rwxp 00000000 00:00 0 
37854000-37878000 rwxp 00000000 00:00 0                                  [heap]
=> 40000000-40004000 r--p 00000000 00:00 0 
                     ^--- not writable
40004000-40008000 ---p 00000000 00:00 0 

unprotectDB is able to Add the Write flag from 0x40000000 ~ 0x40004000 range, but protectDB Remove the Write flag again:

Breakpoint 1, protectDB (addr=addr@entry=1073744056, size=size@entry=1) at /home/zhaixiang/repo/box64/src/custommem.c:2224
2224        dynarec_log(LOG_DEBUG, "protectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
(gdb) bt
#0  protectDB (addr=addr@entry=1073744056, size=size@entry=1) at /home/zhaixiang/repo/box64/src/custommem.c:2224
#1  0x00000000351ad284 in FillBlock64 (addr=addr@entry=1073744056, alternate=alternate@entry=0, is32bits=is32bits@entry=1, inst_max=inst_max@entry=32760, is_new=is_new@entry=1) at /home/zhaixiang/repo/box64/src/dynarec/dynarec_native.c:442
=> #2  0x00000000351aab2c in internalDBGetBlock (addr=addr@entry=1073744056, filladdr=filladdr@entry=1073744056, create=create@entry=1, need_lock=need_lock@entry=1, is32bits=is32bits@entry=1, is_new=is_new@entry=1, emu=0x3d5e1c20) at /home/zhaixiang/repo/box64/src/dynarec/dynablock.c:299
#3  0x00000000351aaeb4 in DBGetBlock (emu=emu@entry=0x3d5e1c20, addr=addr@entry=1073744056, create=create@entry=1, is32bits=is32bits@entry=1) at /home/zhaixiang/repo/box64/src/dynarec/dynablock.c:337
#4  0x000000003484e464 in LinkNext (emu=0x3d5e1c20, addr=1073744056, x2=<optimized out>, x3=0xfffbc49638) at /home/zhaixiang/repo/box64/src/dynarec/dynarec.c:63
#5  0x00000000351e4e5c in la64_next () at /home/zhaixiang/repo/box64/src/dynarec/la64/la64_next.S:39
...
(gdb) p/x addr
$2 = 0x400008b8

Workaround just make test passed:

diff --git a/src/dynarec/dynablock.c b/src/dynarec/dynablock.c
index 768ae144..e4b6095d 100644
--- a/src/dynarec/dynablock.c
+++ b/src/dynarec/dynablock.c
@@ -236,7 +236,11 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
 {
     if (hasAlternate((void*)filladdr))
         return NULL;
+#ifdef LA64
+    const uint32_t req_prot = PROT_EXEC|PROT_READ;
+#else
     const uint32_t req_prot = (box64_pagesize==4096)?(PROT_EXEC|PROT_READ):PROT_READ;
+#endif
     if(BOX64ENV(nodynarec_delay) && (addr>=BOX64ENV(nodynarec_start)) && (addr<BOX64ENV(nodynarec_end)))
         return NULL;
     dynablock_t* block = getDB(addr);

But how to cure really?

Thanks,
Leslie Zhai

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions