Skip to content

Commit 9f34193

Browse files
committed
arm64: mte: Add PROT_MTE support to mmap() and mprotect()
To enable tagging on a memory range, the user must explicitly opt in via a new PROT_MTE flag passed to mmap() or mprotect(). Since this is a new memory type in the AttrIndx field of a pte, simplify the or'ing of these bits over the protection_map[] attributes by making MT_NORMAL index 0. There are two conditions for arch_vm_get_page_prot() to return the MT_NORMAL_TAGGED memory type: (1) the user requested it via PROT_MTE, registered as VM_MTE in the vm_flags, and (2) the vma supports MTE, decided during the mmap() call (only) and registered as VM_MTE_ALLOWED. arch_calc_vm_prot_bits() is responsible for registering the user request as VM_MTE. The newly introduced arch_calc_vm_flag_bits() sets VM_MTE_ALLOWED if the mapping is MAP_ANONYMOUS. An MTE-capable filesystem (RAM-based) may be able to set VM_MTE_ALLOWED during its mmap() file ops call. In addition, update VM_DATA_DEFAULT_FLAGS to allow mprotect(PROT_MTE) on stack or brk area. The Linux mmap() syscall currently ignores unknown PROT_* flags. In the presence of MTE, an mmap(PROT_MTE) on a file which does not support MTE will not report an error and the memory will not be mapped as Normal Tagged. For consistency, mprotect(PROT_MTE) will not report an error either if the memory range does not support MTE. Two subsequent patches in the series will propose tightening of this behaviour. Co-developed-by: Vincenzo Frascino <vincenzo.frascino@arm.com> Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Will Deacon <will@kernel.org>
1 parent b3fbbea commit 9f34193

File tree

7 files changed

+72
-12
lines changed

7 files changed

+72
-12
lines changed

arch/arm64/include/asm/memory.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,18 @@
126126

127127
/*
128128
* Memory types available.
129+
*
130+
* IMPORTANT: MT_NORMAL must be index 0 since vm_get_page_prot() may 'or' in
131+
* the MT_NORMAL_TAGGED memory type for PROT_MTE mappings. Note
132+
* that protection_map[] only contains MT_NORMAL attributes.
129133
*/
130-
#define MT_DEVICE_nGnRnE 0
131-
#define MT_DEVICE_nGnRE 1
132-
#define MT_DEVICE_GRE 2
133-
#define MT_NORMAL_NC 3
134-
#define MT_NORMAL 4
135-
#define MT_NORMAL_WT 5
136-
#define MT_NORMAL_TAGGED 6
134+
#define MT_NORMAL 0
135+
#define MT_NORMAL_TAGGED 1
136+
#define MT_NORMAL_NC 2
137+
#define MT_NORMAL_WT 3
138+
#define MT_DEVICE_nGnRnE 4
139+
#define MT_DEVICE_nGnRE 5
140+
#define MT_DEVICE_GRE 6
137141

138142
/*
139143
* Memory types for Stage-2 translation

arch/arm64/include/asm/mman.h

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,51 @@
99
static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot,
1010
unsigned long pkey __always_unused)
1111
{
12+
unsigned long ret = 0;
13+
1214
if (system_supports_bti() && (prot & PROT_BTI))
13-
return VM_ARM64_BTI;
15+
ret |= VM_ARM64_BTI;
1416

15-
return 0;
17+
if (system_supports_mte() && (prot & PROT_MTE))
18+
ret |= VM_MTE;
19+
20+
return ret;
1621
}
1722
#define arch_calc_vm_prot_bits(prot, pkey) arch_calc_vm_prot_bits(prot, pkey)
1823

24+
static inline unsigned long arch_calc_vm_flag_bits(unsigned long flags)
25+
{
26+
/*
27+
* Only allow MTE on anonymous mappings as these are guaranteed to be
28+
* backed by tags-capable memory. The vm_flags may be overridden by a
29+
* filesystem supporting MTE (RAM-based).
30+
*/
31+
if (system_supports_mte() && (flags & MAP_ANONYMOUS))
32+
return VM_MTE_ALLOWED;
33+
34+
return 0;
35+
}
36+
#define arch_calc_vm_flag_bits(flags) arch_calc_vm_flag_bits(flags)
37+
1938
static inline pgprot_t arch_vm_get_page_prot(unsigned long vm_flags)
2039
{
21-
return (vm_flags & VM_ARM64_BTI) ? __pgprot(PTE_GP) : __pgprot(0);
40+
pteval_t prot = 0;
41+
42+
if (vm_flags & VM_ARM64_BTI)
43+
prot |= PTE_GP;
44+
45+
/*
46+
* There are two conditions required for returning a Normal Tagged
47+
* memory type: (1) the user requested it via PROT_MTE passed to
48+
* mmap() or mprotect() and (2) the corresponding vma supports MTE. We
49+
* register (1) as VM_MTE in the vma->vm_flags and (2) as
50+
* VM_MTE_ALLOWED. Note that the latter can only be set during the
51+
* mmap() call since mprotect() does not accept MAP_* flags.
52+
*/
53+
if ((vm_flags & VM_MTE) && (vm_flags & VM_MTE_ALLOWED))
54+
prot |= PTE_ATTRINDX(MT_NORMAL_TAGGED);
55+
56+
return __pgprot(prot);
2257
}
2358
#define arch_vm_get_page_prot(vm_flags) arch_vm_get_page_prot(vm_flags)
2459

@@ -30,6 +65,9 @@ static inline bool arch_validate_prot(unsigned long prot,
3065
if (system_supports_bti())
3166
supported |= PROT_BTI;
3267

68+
if (system_supports_mte())
69+
supported |= PROT_MTE;
70+
3371
return (prot & ~supported) == 0;
3472
}
3573
#define arch_validate_prot(prot, addr) arch_validate_prot(prot, addr)

arch/arm64/include/asm/page.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ extern int pfn_valid(unsigned long);
4343

4444
#endif /* !__ASSEMBLY__ */
4545

46-
#define VM_DATA_DEFAULT_FLAGS VM_DATA_FLAGS_TSK_EXEC
46+
#define VM_DATA_DEFAULT_FLAGS (VM_DATA_FLAGS_TSK_EXEC | VM_MTE_ALLOWED)
4747

4848
#include <asm-generic/getorder.h>
4949

arch/arm64/include/asm/pgtable.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,8 +681,13 @@ static inline unsigned long p4d_page_vaddr(p4d_t p4d)
681681

682682
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
683683
{
684+
/*
685+
* Normal and Normal-Tagged are two different memory types and indices
686+
* in MAIR_EL1. The mask below has to include PTE_ATTRINDX_MASK.
687+
*/
684688
const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
685-
PTE_PROT_NONE | PTE_VALID | PTE_WRITE | PTE_GP;
689+
PTE_PROT_NONE | PTE_VALID | PTE_WRITE | PTE_GP |
690+
PTE_ATTRINDX_MASK;
686691
/* preserve the hardware dirty information */
687692
if (pte_hw_dirty(pte))
688693
pte = pte_mkdirty(pte);

arch/arm64/include/uapi/asm/mman.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
#include <asm-generic/mman.h>
66

77
#define PROT_BTI 0x10 /* BTI guarded page */
8+
#define PROT_MTE 0x20 /* Normal Tagged mapping */
89

910
#endif /* ! _UAPI__ASM_MMAN_H */

fs/proc/task_mmu.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,10 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
653653
[ilog2(VM_MERGEABLE)] = "mg",
654654
[ilog2(VM_UFFD_MISSING)]= "um",
655655
[ilog2(VM_UFFD_WP)] = "uw",
656+
#ifdef CONFIG_ARM64_MTE
657+
[ilog2(VM_MTE)] = "mt",
658+
[ilog2(VM_MTE_ALLOWED)] = "",
659+
#endif
656660
#ifdef CONFIG_ARCH_HAS_PKEYS
657661
/* These come out via ProtectionKey: */
658662
[ilog2(VM_PKEY_BIT0)] = "",

include/linux/mm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,14 @@ extern unsigned int kobjsize(const void *objp);
340340
# define VM_MAPPED_COPY VM_ARCH_1 /* T if mapped copy of data (nommu mmap) */
341341
#endif
342342

343+
#if defined(CONFIG_ARM64_MTE)
344+
# define VM_MTE VM_HIGH_ARCH_0 /* Use Tagged memory for access control */
345+
# define VM_MTE_ALLOWED VM_HIGH_ARCH_1 /* Tagged memory permitted */
346+
#else
347+
# define VM_MTE VM_NONE
348+
# define VM_MTE_ALLOWED VM_NONE
349+
#endif
350+
343351
#ifndef VM_GROWSUP
344352
# define VM_GROWSUP VM_NONE
345353
#endif

0 commit comments

Comments
 (0)