git: bd7afd9e50b3 - stable/13 - vm_map_protect(): handle stack protection stored in the stack guard

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Fri, 25 Aug 2023 01:08:33 UTC
The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=bd7afd9e50b3a0939354c3e8c8ddcc9f696c92f9

commit bd7afd9e50b3a0939354c3e8c8ddcc9f696c92f9
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-07-25 13:32:28 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-08-25 01:06:44 +0000

    vm_map_protect(): handle stack protection stored in the stack guard
    
    (cherry picked from commit 55be6be12cd95552a46feccb42db984c8d3cbc36)
---
 sys/vm/vm_map.c | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c
index d443c320b799..09e78b3e18f9 100644
--- a/sys/vm/vm_map.c
+++ b/sys/vm/vm_map.c
@@ -2720,7 +2720,22 @@ static void
 vm_map_protect_guard(vm_map_entry_t entry, vm_prot_t new_prot,
     vm_prot_t new_maxprot, int flags)
 {
+	vm_prot_t old_prot;
+
 	MPASS((entry->eflags & MAP_ENTRY_GUARD) != 0);
+	if ((entry->eflags & (MAP_ENTRY_STACK_GAP_UP |
+	    MAP_ENTRY_STACK_GAP_DN)) == 0)
+		return;
+
+	old_prot = PROT_EXTRACT(entry->offset);
+	if ((flags & VM_MAP_PROTECT_SET_MAXPROT) != 0) {
+		entry->offset = PROT_MAX(new_maxprot) |
+		    (new_maxprot & old_prot);
+	}
+	if ((flags & VM_MAP_PROTECT_SET_PROT) != 0) {
+		entry->offset = new_prot | PROT_MAX(
+		    PROT_MAX_EXTRACT(entry->offset));
+	}
 }
 
 /*
@@ -2736,7 +2751,7 @@ vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end,
 	vm_map_entry_t entry, first_entry, in_tran, prev_entry;
 	vm_object_t obj;
 	struct ucred *cred;
-	vm_prot_t check_prot, old_prot;
+	vm_prot_t check_prot, max_prot, old_prot;
 	int rv;
 
 	if (start == end)
@@ -2785,10 +2800,14 @@ again:
 			vm_map_unlock(map);
 			return (KERN_INVALID_ARGUMENT);
 		}
-		if ((entry->eflags & MAP_ENTRY_GUARD) != 0) {
+		if ((entry->eflags & (MAP_ENTRY_GUARD |
+		    MAP_ENTRY_STACK_GAP_DN | MAP_ENTRY_STACK_GAP_UP)) ==
+		    MAP_ENTRY_GUARD)
 			continue;
-		}
-		if (!CONTAINS_BITS(entry->max_protection, check_prot)) {
+		max_prot = (entry->eflags & (MAP_ENTRY_STACK_GAP_DN |
+		    MAP_ENTRY_STACK_GAP_UP)) != 0 ?
+		    PROT_MAX_EXTRACT(entry->offset) : entry->max_protection;
+		if (!CONTAINS_BITS(max_prot, check_prot)) {
 			vm_map_unlock(map);
 			return (KERN_PROTECTION_FAILURE);
 		}