diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2024-01-21 16:57:07 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2024-01-21 16:57:07 +0000 |
commit | be146c0d7880a81b39d42a4995bcef1b8b541158 (patch) | |
tree | 9f492d184bc77980a096a71c64c9a1adfb576bed /sys | |
parent | 77c4c1515c8d0890ab9eb073614a7cb91335eec9 (diff) |
madvise(2) and msync(2) have some memory/mapping destructive ops which should
not be allowed upon immutable memory, instead return EPERM.
Some of these ops are not destructive in OpenBSD, but they are destructive
on other systems, so we take the "all ops" are illegal approach.
Related to this, it should not be allowed to minherit(MAP_INHERIT_ZERO)
immutable regions, or vice versa, calling mimmutable() upon MAP_INHERIT_ZERO
regions, because such a range will be zero'd post-fork in the child.
These now also return EPERM.
Adjusting the madvise / msync behaviour upon immutable memory brings us
closer to the behaviour of the mimmutable clone "mseal" being proposed by
google for inclusion in Linux.
ok kettenis
Diffstat (limited to 'sys')
-rw-r--r-- | sys/uvm/uvm_map.c | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/sys/uvm/uvm_map.c b/sys/uvm/uvm_map.c index e74948b0a58..0cc03de7331 100644 --- a/sys/uvm/uvm_map.c +++ b/sys/uvm/uvm_map.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_map.c,v 1.323 2024/01/21 00:26:14 deraadt Exp $ */ +/* $OpenBSD: uvm_map.c,v 1.324 2024/01/21 16:57:06 deraadt Exp $ */ /* $NetBSD: uvm_map.c,v 1.86 2000/11/27 08:40:03 chs Exp $ */ /* @@ -4166,7 +4166,8 @@ int uvm_map_inherit(struct vm_map *map, vaddr_t start, vaddr_t end, vm_inherit_t new_inheritance) { - struct vm_map_entry *entry; + struct vm_map_entry *entry, *entry1; + int error = EPERM; switch (new_inheritance) { case MAP_INHERIT_NONE: @@ -4193,14 +4194,24 @@ uvm_map_inherit(struct vm_map *map, vaddr_t start, vaddr_t end, else entry = RBT_NEXT(uvm_map_addr, entry); + /* First check for illegal operations */ + entry1 = entry; + while (entry1 != NULL && entry1->start < end) { + if (entry1->etype & UVM_ET_IMMUTABLE) + goto out; + entry1 = RBT_NEXT(uvm_map_addr, entry1); + } + while (entry != NULL && entry->start < end) { UVM_MAP_CLIP_END(map, entry, end); entry->inheritance = new_inheritance; entry = RBT_NEXT(uvm_map_addr, entry); } + error = 0; +out: vm_map_unlock(map); - return (0); + return (error); } #ifdef PMAP_CHECK_COPYIN @@ -4289,7 +4300,8 @@ uvm_map_syscall(struct vm_map *map, vaddr_t start, vaddr_t end) int uvm_map_immutable(struct vm_map *map, vaddr_t start, vaddr_t end, int imut) { - struct vm_map_entry *entry; + struct vm_map_entry *entry, *entry1; + int error = EPERM; if (start > end) return EINVAL; @@ -4306,6 +4318,14 @@ uvm_map_immutable(struct vm_map *map, vaddr_t start, vaddr_t end, int imut) else entry = RBT_NEXT(uvm_map_addr, entry); + /* First check for illegal operations */ + entry1 = entry; + while (entry1 != NULL && entry1->start < end) { + if (entry1->inheritance == MAP_INHERIT_ZERO) + goto out; + entry1 = RBT_NEXT(uvm_map_addr, entry1); + } + while (entry != NULL && entry->start < end) { UVM_MAP_CLIP_END(map, entry, end); if (imut) @@ -4316,6 +4336,8 @@ uvm_map_immutable(struct vm_map *map, vaddr_t start, vaddr_t end, int imut) } map->wserial++; + error = 0; +out: vm_map_unlock(map); return (0); } @@ -4553,9 +4575,13 @@ uvm_map_clean(struct vm_map *map, vaddr_t start, vaddr_t end, int flags) vm_map_lock(map); first = uvm_map_entrybyaddr(&map->addr, start); - /* Make a first pass to check for holes. */ + /* Make a first pass to check for various conditions. */ for (entry = first; entry != NULL && entry->start < end; entry = RBT_NEXT(uvm_map_addr, entry)) { + if (entry->etype & UVM_ET_IMMUTABLE) { + vm_map_unlock(map); + return EPERM; + } if (UVM_ET_ISSUBMAP(entry)) { vm_map_unlock(map); return EINVAL; |