summaryrefslogtreecommitdiff
path: root/sys/uvm
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2022-03-11 19:24:20 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2022-03-11 19:24:20 +0000
commit315898cb62285655b4c17c0ba377bbd9f2d1dac3 (patch)
treec413e6535ccbef742814a54138b7922675f592a4 /sys/uvm
parentfa139867613fcf0817e691d2579ab5d086cd1bbf (diff)
Hold a read lock on the map while copying out data during a sysctl(2) call
to prevent another thread from unmapping the memory and triggering an assertion or even corrupting random physical memory pages. This fix is similar to the change in uvm_glue.c rev. 1.74. However in this case we need to be careful since some sysctl(2) calls look at the map of the current process. In those cases we must not attempt to lock the map again. ok mpi@ Should fix: Reported-by: syzbot+be89fe83d6c004fcb412@syzkaller.appspotmail.com
Diffstat (limited to 'sys/uvm')
-rw-r--r--sys/uvm/uvm_extern.h3
-rw-r--r--sys/uvm/uvm_glue.c20
-rw-r--r--sys/uvm/uvm_io.c4
-rw-r--r--sys/uvm/uvm_map.c20
-rw-r--r--sys/uvm/uvm_map.h5
5 files changed, 40 insertions, 12 deletions
diff --git a/sys/uvm/uvm_extern.h b/sys/uvm/uvm_extern.h
index faa4a2e5449..980c97422ef 100644
--- a/sys/uvm/uvm_extern.h
+++ b/sys/uvm/uvm_extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_extern.h,v 1.158 2021/06/28 11:19:01 mpi Exp $ */
+/* $OpenBSD: uvm_extern.h,v 1.159 2022/03/11 19:24:19 kettenis Exp $ */
/* $NetBSD: uvm_extern.h,v 1.57 2001/03/09 01:02:12 chs Exp $ */
/*
@@ -291,6 +291,7 @@ void uvm_init_percpu(void);
int uvm_io(vm_map_t, struct uio *, int);
#define UVM_IO_FIXPROT 0x01
+#define UVM_IO_RDLOCKED 0x02
vaddr_t uvm_km_alloc1(vm_map_t, vsize_t, vsize_t, boolean_t);
void uvm_km_free(vm_map_t, vaddr_t, vsize_t);
diff --git a/sys/uvm/uvm_glue.c b/sys/uvm/uvm_glue.c
index 206b84e88e2..d8ca78859ea 100644
--- a/sys/uvm/uvm_glue.c
+++ b/sys/uvm/uvm_glue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_glue.c,v 1.81 2022/02/18 09:04:38 kettenis Exp $ */
+/* $OpenBSD: uvm_glue.c,v 1.82 2022/03/11 19:24:19 kettenis Exp $ */
/* $NetBSD: uvm_glue.c,v 1.44 2001/02/06 19:54:44 eeh Exp $ */
/*
@@ -110,13 +110,26 @@ uvm_vslock(struct proc *p, caddr_t addr, size_t len, vm_prot_t access_type)
{
struct vm_map *map = &p->p_vmspace->vm_map;
vaddr_t start, end;
+ int error, mapv;
start = trunc_page((vaddr_t)addr);
end = round_page((vaddr_t)addr + len);
if (end <= start)
return (EINVAL);
- return uvm_fault_wire(map, start, end, access_type);
+ vm_map_lock_read(map);
+retry:
+ mapv = map->timestamp;
+ vm_map_unlock_read(map);
+
+ if ((error = uvm_fault_wire(map, start, end, access_type)))
+ return (error);
+
+ vm_map_lock_read(map);
+ if (mapv != map->timestamp)
+ goto retry;
+
+ return (0);
}
/*
@@ -133,7 +146,8 @@ uvm_vsunlock(struct proc *p, caddr_t addr, size_t len)
end = round_page((vaddr_t)addr + len);
KASSERT(end > start);
- uvm_fault_unwire(&p->p_vmspace->vm_map, start, end);
+ uvm_fault_unwire_locked(&p->p_vmspace->vm_map, start, end);
+ vm_map_unlock_read(&p->p_vmspace->vm_map);
}
/*
diff --git a/sys/uvm/uvm_io.c b/sys/uvm/uvm_io.c
index 96a9ba543b1..e18df842fe1 100644
--- a/sys/uvm/uvm_io.c
+++ b/sys/uvm/uvm_io.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_io.c,v 1.27 2021/03/20 10:24:21 mpi Exp $ */
+/* $OpenBSD: uvm_io.c,v 1.28 2022/03/11 19:24:19 kettenis Exp $ */
/* $NetBSD: uvm_io.c,v 1.12 2000/06/27 17:29:23 mrg Exp $ */
/*
@@ -86,6 +86,8 @@ uvm_io(vm_map_t map, struct uio *uio, int flags)
extractflags = 0;
if (flags & UVM_IO_FIXPROT)
extractflags |= UVM_EXTRACT_FIXPROT;
+ if (flags & UVM_IO_RDLOCKED)
+ extractflags |= UVM_EXTRACT_RDLOCKED;
/*
* step 1: main loop... while we've got data to move
diff --git a/sys/uvm/uvm_map.c b/sys/uvm/uvm_map.c
index ab114029180..98aa7d4326e 100644
--- a/sys/uvm/uvm_map.c
+++ b/sys/uvm/uvm_map.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_map.c,v 1.288 2022/02/15 11:54:19 kn Exp $ */
+/* $OpenBSD: uvm_map.c,v 1.289 2022/03/11 19:24:19 kettenis Exp $ */
/* $NetBSD: uvm_map.c,v 1.86 2000/11/27 08:40:03 chs Exp $ */
/*
@@ -4522,7 +4522,12 @@ uvm_map_extract(struct vm_map *srcmap, vaddr_t start, vsize_t len,
return 0;
/* Acquire lock on srcmap. */
- vm_map_lock(srcmap);
+ if (flags & UVM_EXTRACT_RDLOCKED) {
+ vm_map_busy(srcmap);
+ vm_map_upgrade(srcmap);
+ vm_map_unbusy(srcmap);
+ } else
+ vm_map_lock(srcmap);
/* Lock srcmap, lookup first and last entry in <start,len>. */
first = uvm_map_entrybyaddr(&srcmap->addr, start);
@@ -4624,7 +4629,10 @@ fail2:
vm_map_unlock(kernel_map);
fail:
- vm_map_unlock(srcmap);
+ if (flags & UVM_EXTRACT_RDLOCKED)
+ vm_map_downgrade(srcmap);
+ else
+ vm_map_unlock(srcmap);
uvm_unmap_detach(&dead, 0);
@@ -5581,7 +5589,9 @@ uvm_map_fill_vmmap(struct vm_map *map, struct kinfo_vmentry *kve,
*/
start = (vaddr_t)kve[0].kve_start;
- vm_map_lock(map);
+ vm_map_busy(map);
+ vm_map_upgrade(map);
+ vm_map_unbusy(map);
RBT_FOREACH(entry, uvm_map_addr, &map->addr) {
if (cnt == maxcnt) {
error = ENOMEM;
@@ -5605,7 +5615,7 @@ uvm_map_fill_vmmap(struct vm_map *map, struct kinfo_vmentry *kve,
kve++;
cnt++;
}
- vm_map_unlock(map);
+ vm_map_downgrade(map);
KASSERT(cnt <= maxcnt);
diff --git a/sys/uvm/uvm_map.h b/sys/uvm/uvm_map.h
index 24bf9fd7ad1..8d0d1c289f7 100644
--- a/sys/uvm/uvm_map.h
+++ b/sys/uvm/uvm_map.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_map.h,v 1.73 2022/02/11 09:25:04 kn Exp $ */
+/* $OpenBSD: uvm_map.h,v 1.74 2022/03/11 19:24:19 kettenis Exp $ */
/* $NetBSD: uvm_map.h,v 1.24 2001/02/18 21:19:08 chs Exp $ */
/*
@@ -116,7 +116,8 @@
/*
* extract flags
*/
-#define UVM_EXTRACT_FIXPROT 0x8 /* set prot to maxprot as we go */
+#define UVM_EXTRACT_FIXPROT 0x1 /* set prot to maxprot as we go */
+#define UVM_EXTRACT_RDLOCKED 0x2 /* map is already read-locked */
#endif /* _KERNEL */