From 9b65fa69407808e710748875b0af98902110f128 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Sun, 30 Jul 2023 00:00:51 +0300 Subject: [PATCH] linuxolator: implement Linux' PROT_GROWSDOWN From the Linux man page for mprotect(2): PROT_GROWSDOWN Apply the protection mode down to the beginning of a mapping that grows downward (which should be a stack segment or a segment mapped with the MAP_GROWSDOWN flag set). Reported by: dchagin Reviewed by: alc, markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D41099 --- sys/compat/freebsd32/freebsd32_misc.c | 2 +- sys/compat/linux/linux_mmap.c | 14 ++++++++++---- sys/sys/syscallsubr.h | 3 ++- sys/vm/vm_mmap.c | 9 +++++---- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index b7ad379df6e0..07ad68d56037 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -512,7 +512,7 @@ freebsd32_mprotect(struct thread *td, struct freebsd32_mprotect_args *uap) prot |= PROT_EXEC; #endif return (kern_mprotect(td, (uintptr_t)PTRIN(uap->addr), uap->len, - prot)); + prot, 0)); } int diff --git a/sys/compat/linux/linux_mmap.c b/sys/compat/linux/linux_mmap.c index 07df6f5fd43d..580f15379e31 100644 --- a/sys/compat/linux/linux_mmap.c +++ b/sys/compat/linux/linux_mmap.c @@ -229,16 +229,22 @@ linux_mmap_common(struct thread *td, uintptr_t addr, size_t len, int prot, int linux_mprotect_common(struct thread *td, uintptr_t addr, size_t len, int prot) { + int flags = 0; - /* XXX Ignore PROT_GROWSDOWN and PROT_GROWSUP for now. */ - prot &= ~(LINUX_PROT_GROWSDOWN | LINUX_PROT_GROWSUP); - if ((prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) != 0) + /* XXX Ignore PROT_GROWSUP for now. */ + prot &= ~LINUX_PROT_GROWSUP; + if ((prot & ~(LINUX_PROT_GROWSDOWN | PROT_READ | PROT_WRITE | + PROT_EXEC)) != 0) return (EINVAL); + if ((prot & LINUX_PROT_GROWSDOWN) != 0) { + prot &= ~LINUX_PROT_GROWSDOWN; + flags |= VM_MAP_PROTECT_GROWSDOWN; + } #if defined(__amd64__) linux_fixup_prot(td, &prot); #endif - return (kern_mprotect(td, addr, len, prot)); + return (kern_mprotect(td, addr, len, prot, flags)); } /* diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index 64f1b16f92b9..660b70136714 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -216,7 +216,8 @@ int kern_mmap(struct thread *td, const struct mmap_req *mrp); int kern_mmap_racct_check(struct thread *td, struct vm_map *map, vm_size_t size); int kern_mmap_maxprot(struct proc *p, int prot); -int kern_mprotect(struct thread *td, uintptr_t addr, size_t size, int prot); +int kern_mprotect(struct thread *td, uintptr_t addr, size_t size, + int prot, int flags); int kern_msgctl(struct thread *, int, int, struct msqid_ds *); int kern_msgrcv(struct thread *, int, void *, size_t, long, int, long *); int kern_msgsnd(struct thread *, int, const void *, size_t, int, long); diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index 328fef007b1e..7876a055ca91 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -658,16 +658,17 @@ int sys_mprotect(struct thread *td, struct mprotect_args *uap) { - return (kern_mprotect(td, (uintptr_t)uap->addr, uap->len, uap->prot)); + return (kern_mprotect(td, (uintptr_t)uap->addr, uap->len, + uap->prot, 0)); } int -kern_mprotect(struct thread *td, uintptr_t addr0, size_t size, int prot) +kern_mprotect(struct thread *td, uintptr_t addr0, size_t size, int prot, + int flags) { vm_offset_t addr; vm_size_t pageoff; int vm_error, max_prot; - int flags; addr = addr0; if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) @@ -687,7 +688,7 @@ kern_mprotect(struct thread *td, uintptr_t addr0, size_t size, int prot) if (addr + size < addr) return (EINVAL); - flags = VM_MAP_PROTECT_SET_PROT; + flags |= VM_MAP_PROTECT_SET_PROT; if (max_prot != 0) flags |= VM_MAP_PROTECT_SET_MAXPROT; vm_error = vm_map_protect(&td->td_proc->p_vmspace->vm_map,