From: deraadt Date: Sun, 21 Jan 2024 16:57:06 +0000 (+0000) Subject: madvise(2) and msync(2) have some memory/mapping destructive ops which should X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=114aad1984406bb6d9522da21182f9fcf7b0f369;p=openbsd 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 --- 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;