Hi,

I'm starting to help in the development of the dt device.

I'm stuck on permission handling of memory. I'm trying to allocate a
page in kernel with read/write protections, fill the allocated page
with data then change the permissions to  read/exec.

Snippet of my code:

 addr = uvm_km_alloc(kernel_map, PAGE_SIZE);

    [...] (memcpy data in allocated page)

 uvm_map_protect(kernel_map, addr, addr + PAGE_SIZE, PROT_READ
                                            | PROT_EXEC, FALSE)))

It triggers the following error at boot time when executing
the uvm_map_protect function.

uvm_fault(0xffffffff81fb2c90, 0x7ffec0008000, 0, 2) -> e kernel: page fault
trap, code=0 Stopped at    pmap_write_protect+0x1f5:  lock andq
$-0x3,0(%rdi)

Trace:

pmap_write_protect(ffffffff82187b28,ffff80002255b000,ffff80002255c000,
    5,50e8b70481f4f622,fffffd81b6567e70) at pmap_write_protect+0x212
uvm_map_protect(ffffffff82129ae0,ffff80002255b000,ffff80002255c000
    ,5,0,ffffffff82129ae0) at uvm_map_protect+0x501
dt_alloc_kprobe(ffffffff815560e0,ffff800000173900,e7ef01a2855152cc,
    ffffffff82395c98,0,ffffffff815560e0) at dt_alloc_kprobe+0x1ff
dt_prov_kprobe_init(2333e28db00d3edd,0,ffffffff82121150,0,0,
    ffffffff824d9008) at dt_prov_kprobe_init+0x1d9
dtattach(1,ffffffff821fb384,f,1,c2ee1c3f472154e,2dda28) at dtattach+0x5d
main(0,0,0,0,0,1) at main+0x419

The problem comes from the loop in pmap_write_protect
(sys/arch/amd64/amd64/pmap.c:2108) that is executed
infinity in my case.

Entry of function pmap_write_protect:
    sva:  FFFF80002250A000
    eva:  FFFF80002250B000

After &= PG_FRAME (line 2098-2099)
    sva= F80002250A000
    eva= F80002250B000

 loop:  (ligne 2108)

     first iteration:
        va           = F80002250A000
        eva         = F80002250B000
        blockend = 0800122400000

    second iteration:
        va           = 0800122400000
        eva         = F80002250B000
        blockend = 0800222400000

We can see that the problem is that the "va" variable has lost
her 4 upper set bits (48 to 51).
So now the comparison between "va" and "eva" is always false and it
loops indefinitely because "va" 4 upper bits are clean each iteration.

The fix that I found is to clear the 4 same bits in "eva".
It can be done with this mask:
      new_mask =  0000FFFFFFFFF000
      PG_FRAME =  000FFFFFFFFFF000


Diff with quick dirty fix:

diff --git a/sys/arch/amd64/amd64/pmap.c b/sys/arch/amd64/amd64/pmap.c
index 10ab3da2949..2783c9d26a5 100644
--- a/sys/arch/amd64/amd64/pmap.c
+++ b/sys/arch/amd64/amd64/pmap.c
@@ -2105,10 +2105,12 @@ pmap_write_protect(struct pmap *pmap, vaddr_t sva, vaddr_t eva, vm_prot_t prot)
        if ((eva - sva > 32 * PAGE_SIZE) && sva < VM_MIN_KERNEL_ADDRESS)
                shootall = 1;

-       for (va = sva; va < eva ; va = blockend) {
-               blockend = (va & L2_FRAME) + NBPD_L2;
-               if (blockend > eva)
-                       blockend = eva;
+    vaddr_t tmp_eva = eva & 0xFFFFFFFFF000UL;
+    vaddr_t tmp_sva = sva & 0xFFFFFFFFF000UL;
+    for (va = tmp_sva; va < tmp_eva ; va = blockend) {
+        blockend = (va & L2_FRAME) + NBPD_L2;
+        if (blockend > tmp_eva)
+            blockend = tmp_eva;

                /*
                 * XXXCDC: our PTE mappings should never be write-protected!


The problem is solved at boot time (I am able to boot without crashing).
But during the execution, we I jump on the page
(with read and exec permissions), the OS completely freeze without
error message, I can't launch the kernel debugger and I don't know how
debug it further.

Does anyone have an idea how to fix this issue?

Thanks

--
Tom Rollet

Reply via email to