[PATCH v8 42/43] mm: add arch hook to validate mmap() prot flags

Catalin Marinas catalin.marinas at arm.com
Tue Mar 12 12:53:01 PDT 2024


On Wed, Feb 14, 2024 at 01:29:28PM +0100, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb at kernel.org>
> 
> Add a hook to permit architectures to perform validation on the prot
> flags passed to mmap(), like arch_validate_prot() does for mprotect().
> This will be used by arm64 to reject PROT_WRITE+PROT_EXEC mappings on
> configurations that run with WXN enabled.
> 
> Reviewed-by: Kees Cook <keescook at chromium.org>
> Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> ---
>  include/linux/mman.h | 15 +++++++++++++++
>  mm/mmap.c            |  3 +++
>  2 files changed, 18 insertions(+)
> 
> diff --git a/include/linux/mman.h b/include/linux/mman.h
> index dc7048824be8..ec5e7f606e43 100644
> --- a/include/linux/mman.h
> +++ b/include/linux/mman.h
> @@ -124,6 +124,21 @@ static inline bool arch_validate_flags(unsigned long flags)
>  #define arch_validate_flags arch_validate_flags
>  #endif
>  
> +#ifndef arch_validate_mmap_prot
> +/*
> + * This is called from mmap(), which ignores unknown prot bits so the default
> + * is to accept anything.
> + *
> + * Returns true if the prot flags are valid
> + */
> +static inline bool arch_validate_mmap_prot(unsigned long prot,
> +					   unsigned long addr)
> +{
> +	return true;
> +}
> +#define arch_validate_mmap_prot arch_validate_mmap_prot
> +#endif
> +
>  /*
>   * Optimisation macro.  It is equivalent to:
>   *      (x & bit1) ? bit2 : 0
> diff --git a/mm/mmap.c b/mm/mmap.c
> index d89770eaab6b..977a8c3fd9f5 100644
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -1229,6 +1229,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
>  		if (!(file && path_noexec(&file->f_path)))
>  			prot |= PROT_EXEC;
>  
> +	if (!arch_validate_mmap_prot(prot, addr))
> +		return -EACCES;
> +
>  	/* force arch specific MAP_FIXED handling in get_unmapped_area */
>  	if (flags & MAP_FIXED_NOREPLACE)
>  		flags |= MAP_FIXED;

While writing the pull request for Linus (and looking to justify this
change), I realised that we already have arch_validate_flags() that can
do a similar check but on VM_* flags instead of PROT_* (we use it for
VM_MTE checks). What was the reason for adding a new hook? The only
difference is that here it returns -EACCESS while on
arch_validate_flags() failure it would return -EINVAL. It probably makes
more to return -EACCESS as it matches map_deny_write_exec() but with
your patches we are inconsistent between mmap() and mprotect() errors
(the latter is still -EINVAL).

It also got me thinking on whether we could use this as a hardened
version of the MDWE feature instead a CPU feature (though we'd end up
context-switching this SCTLR_EL1 bit). I think your patches have been
around before the MDWE feature was added to the kernel.

Sorry for not catching this early.

-- 
Catalin



More information about the linux-arm-kernel mailing list