Index | Thread | Search

From:
Martin Pieuchot <mpi@grenadille.net>
Subject:
uvm_vslock_device(9) fix
To:
tech@openbsd.org
Date:
Mon, 15 Dec 2025 18:33:31 +0100

Download raw body.

Thread
  • Martin Pieuchot:

    uvm_vslock_device(9) fix

Syzkaller managed to reproduce the "address not in map" bug that we
fixed for vslock(9) some months ago:
  https://syzkaller.appspot.com/bug?extid=ed3d78e6268404b528d5

Diff below adapts the previous fix to uvm_vslock_device(9) and avoid an
unlock/relock dance by using vm_map_downgrade().

ok?

Index: uvm/uvm_glue.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_glue.c,v
diff -u -p -r1.94 uvm_glue.c
--- uvm/uvm_glue.c	11 Sep 2025 15:28:40 -0000	1.94
+++ uvm/uvm_glue.c	15 Dec 2025 17:18:05 -0000
@@ -152,7 +152,7 @@ uvm_vslock_device(struct proc *p, void *
 	vaddr_t start, end, off;
 	vaddr_t sva, va;
 	vsize_t sz;
-	int error, mapv, i;
+	int error, i;
 
 	start = trunc_page((vaddr_t)addr);
 	end = round_page((vaddr_t)addr + len);
@@ -161,17 +161,15 @@ uvm_vslock_device(struct proc *p, void *
 	if (end <= start)
 		return (EINVAL);
 
-	vm_map_lock_read(map);
-retry:
-	mapv = map->timestamp;
-	vm_map_unlock_read(map);
-
-	if ((error = uvm_fault_wire(map, start, end, access_type)))
+	vm_map_lock(map);
+	error = uvm_map_pageable(map, start, end, FALSE,
+	    UVM_LK_ENTER|UVM_LK_EXIT);
+	if (error != 0) {
+		vm_map_unlock(map);
 		return (error);
+	}
 
-	vm_map_lock_read(map);
-	if (mapv != map->timestamp)
-		goto retry;
+	vm_map_downgrade(map);
 
 	npages = atop(sz);
 	for (i = 0; i < npages; i++) {
@@ -220,8 +218,8 @@ retry:
 out_unmap:
 	km_free((void *)sva, sz, &kv_any, &kp_none);
 out_unwire:
-	uvm_fault_unwire_locked(map, start, end);
 	vm_map_unlock_read(map);
+	uvm_map_pageable(map, start, end, TRUE, 0);
 	return (error);
 }
 
@@ -245,8 +243,8 @@ uvm_vsunlock_device(struct proc *p, void
 	if (map)
 		copyout(map, addr, len);
 
-	uvm_fault_unwire_locked(&p->p_vmspace->vm_map, start, end);
 	vm_map_unlock_read(&p->p_vmspace->vm_map);
+	uvm_map_pageable(&p->p_vmspace->vm_map, start, end, TRUE, 0);
 
 	if (!map)
 		return;