diff options
| author | Mark Johnston <markj@FreeBSD.org> | 2026-03-31 13:37:43 +0000 |
|---|---|---|
| committer | Mark Johnston <markj@FreeBSD.org> | 2026-04-21 15:41:34 +0000 |
| commit | ca87c0b8e396fff01d55f1985c2556934c35a950 (patch) | |
| tree | 5ca4b9746ecb10b11c330734133c27fe1f3646f6 /sys/vm | |
| parent | 093903a8d4c05d1adff79895a52a3e3009ff07a7 (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.c | 32 | ||||
| -rw-r--r-- | sys/vm/vm_map.h | 1 |
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, |
