summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2024-01-21 16:57:07 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2024-01-21 16:57:07 +0000
commitbe146c0d7880a81b39d42a4995bcef1b8b541158 (patch)
tree9f492d184bc77980a096a71c64c9a1adfb576bed /sys
parent77c4c1515c8d0890ab9eb073614a7cb91335eec9 (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.c36
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;