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