aboutsummaryrefslogtreecommitdiff
path: root/sys/vm
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2026-03-31 13:37:43 +0000
committerMark Johnston <markj@FreeBSD.org>2026-04-21 15:41:34 +0000
commitca87c0b8e396fff01d55f1985c2556934c35a950 (patch)
tree5ca4b9746ecb10b11c330734133c27fe1f3646f6 /sys/vm
parent093903a8d4c05d1adff79895a52a3e3009ff07a7 (diff)
pkru: Fix handling of 1GB largepage mappings
pmap_pkru_update_range() did not handle the case where a PDPE has PG_PS set. More generally, the SET_PKRU and CLEAR_PKRU sysarch implementations did not check whether the request covers a "boundary" vm map entry. Fix this, add the missing PG_PS test, and add some tests. Approved by: so Security: FreeBSD-SA-26:11.amd64 Security: CVE-2026-6386 Reported by: Nicholas Carlini <npc@anthropic.com> Reviewed by: kib, alc Differential Revision: https://reviews.freebsd.org/D56184
Diffstat (limited to 'sys/vm')
-rw-r--r--sys/vm/vm_map.c32
-rw-r--r--sys/vm/vm_map.h1
2 files changed, 33 insertions, 0 deletions
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c
index b8295bb2108d..63bdce9d60f8 100644
--- a/sys/vm/vm_map.c
+++ b/sys/vm/vm_map.c
@@ -4163,6 +4163,38 @@ vm_map_check_protection(vm_map_t map, vm_offset_t start, vm_offset_t end,
}
/*
+ * Check whether the specified range partially overlaps a map entry with
+ * fixed boundaries, and return false if so.
+ *
+ * The map must be locked.
+ */
+bool
+vm_map_check_boundary(vm_map_t map, vm_offset_t start, vm_offset_t end)
+{
+ vm_map_entry_t entry;
+ int bdry_idx;
+
+ if (!vm_map_range_valid(map, start, end))
+ return (false);
+ if (start == end)
+ return (true);
+
+ if (vm_map_lookup_entry(map, start, &entry)) {
+ bdry_idx = MAP_ENTRY_SPLIT_BOUNDARY_INDEX(entry);
+ if (bdry_idx != 0 &&
+ (start & (pagesizes[bdry_idx] - 1)) != 0)
+ return (false);
+ }
+ if (vm_map_lookup_entry(map, end - 1, &entry)) {
+ bdry_idx = MAP_ENTRY_SPLIT_BOUNDARY_INDEX(entry);
+ if (bdry_idx != 0 &&
+ (end & (pagesizes[bdry_idx] - 1)) != 0)
+ return (false);
+ }
+ return (true);
+}
+
+/*
*
* vm_map_copy_swap_object:
*
diff --git a/sys/vm/vm_map.h b/sys/vm/vm_map.h
index 6af3dba42685..0b0edb24a64d 100644
--- a/sys/vm/vm_map.h
+++ b/sys/vm/vm_map.h
@@ -479,6 +479,7 @@ vm_map_entry_read_succ(void *token, struct vm_map_entry *const clone,
#endif /* ! _KERNEL */
#ifdef _KERNEL
+bool vm_map_check_boundary(vm_map_t, vm_offset_t, vm_offset_t);
boolean_t vm_map_check_protection (vm_map_t, vm_offset_t, vm_offset_t, vm_prot_t);
int vm_map_delete(vm_map_t, vm_offset_t, vm_offset_t);
int vm_map_find(vm_map_t, vm_object_t, vm_ooffset_t, vm_offset_t *, vm_size_t,