summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2020-03-04 21:15:38 +0000
committerkettenis <kettenis@openbsd.org>2020-03-04 21:15:38 +0000
commit003533bf0926d96714c78f5d18235ab424aeb529 (patch)
tree30cdc8e4c5ffc0c867e9f887190e9038ec6f9ac3
parentAvoid passing a NULL name to retrieve(), use "." instead. (diff)
downloadwireguard-openbsd-003533bf0926d96714c78f5d18235ab424aeb529.tar.xz
wireguard-openbsd-003533bf0926d96714c78f5d18235ab424aeb529.zip
Do not count pages mapped as PROT_NONE against the RLIMIT_DATA limit.
Instead count (and check the limit) when their protection gets flipped from PROT_NONE to something that permits access. This means that mprotect(2) may now fail if changing the protection would exceed RLIMIT_DATA. This helps code (such as Chromium's JavaScript interpreter that reserves large chunks of address space but populates it sparsely. ok deraadt@, otto@, kurt@, millert@, robert@
-rw-r--r--sys/uvm/uvm_map.c49
-rw-r--r--sys/uvm/uvm_mmap.c12
2 files changed, 51 insertions, 10 deletions
diff --git a/sys/uvm/uvm_map.c b/sys/uvm/uvm_map.c
index 0f82229a407..5681cbefb42 100644
--- a/sys/uvm/uvm_map.c
+++ b/sys/uvm/uvm_map.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_map.c,v 1.262 2019/12/30 23:58:38 jsg Exp $ */
+/* $OpenBSD: uvm_map.c,v 1.263 2020/03/04 21:15:38 kettenis Exp $ */
/* $NetBSD: uvm_map.c,v 1.86 2000/11/27 08:40:03 chs Exp $ */
/*
@@ -1105,7 +1105,10 @@ uvm_mapanon(struct vm_map *map, vaddr_t *addr, vsize_t sz,
/* Update map and process statistics. */
map->size += sz;
- ((struct vmspace *)map)->vm_dused += uvmspace_dused(map, *addr, *addr + sz);
+ if (prot != PROT_NONE) {
+ ((struct vmspace *)map)->vm_dused +=
+ uvmspace_dused(map, *addr, *addr + sz);
+ }
unlock:
vm_map_unlock(map);
@@ -1381,7 +1384,8 @@ uvm_map(struct vm_map *map, vaddr_t *addr, vsize_t sz,
/* Update map and process statistics. */
if (!(flags & UVM_FLAG_HOLE)) {
map->size += sz;
- if ((map->flags & VM_MAP_ISVMSPACE) && uobj == NULL) {
+ if ((map->flags & VM_MAP_ISVMSPACE) && uobj == NULL &&
+ prot != PROT_NONE) {
((struct vmspace *)map)->vm_dused +=
uvmspace_dused(map, *addr, *addr + sz);
}
@@ -2229,6 +2233,7 @@ uvm_unmap_remove(struct vm_map *map, vaddr_t start, vaddr_t end,
/* Update space usage. */
if ((map->flags & VM_MAP_ISVMSPACE) &&
entry->object.uvm_obj == NULL &&
+ entry->protection != PROT_NONE &&
!UVM_ET_ISHOLE(entry)) {
((struct vmspace *)map)->vm_dused -=
uvmspace_dused(map, entry->start, entry->end);
@@ -2986,7 +2991,8 @@ vmspace_validate(struct vm_map *map)
RBT_FOREACH(iter, uvm_map_addr, &map->addr) {
imin = imax = iter->start;
- if (UVM_ET_ISHOLE(iter) || iter->object.uvm_obj != NULL)
+ if (UVM_ET_ISHOLE(iter) || iter->object.uvm_obj != NULL ||
+ iter->prot != PROT_NONE)
continue;
/*
@@ -3288,6 +3294,7 @@ uvm_map_protect(struct vm_map *map, vaddr_t start, vaddr_t end,
struct vm_map_entry *first, *iter;
vm_prot_t old_prot;
vm_prot_t mask;
+ vsize_t dused;
int error;
if (start > end)
@@ -3297,6 +3304,7 @@ uvm_map_protect(struct vm_map *map, vaddr_t start, vaddr_t end,
if (start >= end)
return 0;
+ dused = 0;
error = 0;
vm_map_lock(map);
@@ -3316,6 +3324,12 @@ uvm_map_protect(struct vm_map *map, vaddr_t start, vaddr_t end,
if (iter->start == iter->end || UVM_ET_ISHOLE(iter))
continue;
+ old_prot = iter->protection;
+ if (old_prot == PROT_NONE && new_prot != old_prot) {
+ dused += uvmspace_dused(
+ map, MAX(start, iter->start), MIN(end, iter->end));
+ }
+
if (UVM_ET_ISSUBMAP(iter)) {
error = EINVAL;
goto out;
@@ -3329,6 +3343,17 @@ uvm_map_protect(struct vm_map *map, vaddr_t start, vaddr_t end,
panic("uvm_map_protect: kernel map W^X violation requested");
}
+ /* Check limits. */
+ if (dused > 0 && (map->flags & VM_MAP_ISVMSPACE)) {
+ vsize_t limit = lim_cur(RLIMIT_DATA);
+ dused = ptoa(dused);
+ if (limit < dused ||
+ limit - dused < ptoa(((struct vmspace *)map)->vm_dused)) {
+ error = ENOMEM;
+ goto out;
+ }
+ }
+
/* Fix protections. */
for (iter = first; iter != NULL && iter->start < end;
iter = RBT_NEXT(uvm_map_addr, iter)) {
@@ -3372,6 +3397,19 @@ uvm_map_protect(struct vm_map *map, vaddr_t start, vaddr_t end,
if (iter->protection & PROT_WRITE)
map->wserial++;
+ if (map->flags & VM_MAP_ISVMSPACE) {
+ if (old_prot == PROT_NONE) {
+ ((struct vmspace *)map)->vm_dused +=
+ uvmspace_dused(map, iter->start,
+ iter->end);
+ }
+ if (iter->protection == PROT_NONE) {
+ ((struct vmspace *)map)->vm_dused -=
+ uvmspace_dused(map, iter->start,
+ iter->end);
+ }
+ }
+
/* update pmap */
if ((iter->protection & mask) == PROT_NONE &&
VM_MAPENT_ISWIRED(iter)) {
@@ -4069,7 +4107,8 @@ uvmspace_fork(struct process *pr)
/* Update process statistics. */
if (!UVM_ET_ISHOLE(new_entry))
new_map->size += new_entry->end - new_entry->start;
- if (!UVM_ET_ISOBJ(new_entry) && !UVM_ET_ISHOLE(new_entry)) {
+ if (!UVM_ET_ISOBJ(new_entry) && !UVM_ET_ISHOLE(new_entry) &&
+ new_entry->protection != PROT_NONE) {
vm2->vm_dused += uvmspace_dused(
new_map, new_entry->start, new_entry->end);
}
diff --git a/sys/uvm/uvm_mmap.c b/sys/uvm/uvm_mmap.c
index 8e9bd66bc7b..29d79afb103 100644
--- a/sys/uvm/uvm_mmap.c
+++ b/sys/uvm/uvm_mmap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_mmap.c,v 1.160 2019/11/29 06:34:46 deraadt Exp $ */
+/* $OpenBSD: uvm_mmap.c,v 1.161 2020/03/04 21:15:39 kettenis Exp $ */
/* $NetBSD: uvm_mmap.c,v 1.49 2001/02/18 21:19:08 chs Exp $ */
/*
@@ -404,10 +404,12 @@ is_anon: /* label for SunOS style /dev/zero */
if ((flags & __MAP_NOFAULT) != 0)
return EINVAL;
- limit = lim_cur(RLIMIT_DATA);
- if (limit < size ||
- limit - size < ptoa(p->p_vmspace->vm_dused)) {
- return ENOMEM;
+ if (prot != PROT_NONE) {
+ limit = lim_cur(RLIMIT_DATA);
+ if (limit < size ||
+ limit - size < ptoa(p->p_vmspace->vm_dused)) {
+ return ENOMEM;
+ }
}
/*