* [PATCH v2 01/19] arm64: alternative: Allow alternative_insn to always issue the first instruction
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 02/19] arm64: mte: system register definitions Catalin Marinas
` (17 subsequent siblings)
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
There are situations where we do not want to disable the whole block
based on a config option, only the alternative part while keeping the
first instruction. Improve the alternative_insn assembler macro to take
a 'first_insn' argument, default 0 to preserve the current behaviour.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm64/include/asm/alternative.h | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h
index 324e7d5ab37e..44083424d7aa 100644
--- a/arch/arm64/include/asm/alternative.h
+++ b/arch/arm64/include/asm/alternative.h
@@ -111,7 +111,11 @@ static inline void apply_alternatives_module(void *start, size_t length) { }
.byte \alt_len
.endm
-.macro alternative_insn insn1, insn2, cap, enable = 1
+/*
+ * Disable the whole block if enable == 0, unless first_insn == 1 in which
+ * case insn1 will always be issued but without an alternative insn2.
+ */
+.macro alternative_insn insn1, insn2, cap, enable = 1, first_insn = 0
.if \enable
661: \insn1
662: .pushsection .altinstructions, "a"
@@ -122,6 +126,8 @@ static inline void apply_alternatives_module(void *start, size_t length) { }
664: .popsection
.org . - (664b-663b) + (662b-661b)
.org . - (662b-661b) + (664b-663b)
+ .elseif \first_insn
+ \insn1
.endif
.endm
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 02/19] arm64: mte: system register definitions
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 01/19] arm64: alternative: Allow alternative_insn to always issue the first instruction Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 03/19] arm64: mte: CPU feature detection and initial sysreg configuration Catalin Marinas
` (16 subsequent siblings)
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
From: Vincenzo Frascino <vincenzo.frascino@arm.com>
Add Memory Tagging Extension system register definitions together with
the relevant bitfields.
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Co-developed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
Notes:
v2:
- Added SET_PSTATE_TCO() macro.
arch/arm64/include/asm/kvm_arm.h | 1 +
arch/arm64/include/asm/sysreg.h | 54 ++++++++++++++++++++++++++++
arch/arm64/include/uapi/asm/ptrace.h | 1 +
arch/arm64/kernel/ptrace.c | 2 +-
4 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 6e5d839f42b5..0b25f9a81c57 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -12,6 +12,7 @@
#include <asm/types.h>
/* Hyp Configuration Register (HCR) bits */
+#define HCR_ATA (UL(1) << 56)
#define HCR_FWB (UL(1) << 46)
#define HCR_API (UL(1) << 41)
#define HCR_APK (UL(1) << 40)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index b91570ff9db1..9b95315c5c2a 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -89,10 +89,12 @@
#define PSTATE_PAN pstate_field(0, 4)
#define PSTATE_UAO pstate_field(0, 3)
#define PSTATE_SSBS pstate_field(3, 1)
+#define PSTATE_TCO pstate_field(3, 4)
#define SET_PSTATE_PAN(x) __emit_inst(0xd500401f | PSTATE_PAN | ((!!x) << PSTATE_Imm_shift))
#define SET_PSTATE_UAO(x) __emit_inst(0xd500401f | PSTATE_UAO | ((!!x) << PSTATE_Imm_shift))
#define SET_PSTATE_SSBS(x) __emit_inst(0xd500401f | PSTATE_SSBS | ((!!x) << PSTATE_Imm_shift))
+#define SET_PSTATE_TCO(x) __emit_inst(0xd500401f | PSTATE_TCO | ((!!x) << PSTATE_Imm_shift))
#define __SYS_BARRIER_INSN(CRm, op2, Rt) \
__emit_inst(0xd5000000 | sys_insn(0, 3, 3, (CRm), (op2)) | ((Rt) & 0x1f))
@@ -172,6 +174,8 @@
#define SYS_SCTLR_EL1 sys_reg(3, 0, 1, 0, 0)
#define SYS_ACTLR_EL1 sys_reg(3, 0, 1, 0, 1)
#define SYS_CPACR_EL1 sys_reg(3, 0, 1, 0, 2)
+#define SYS_RGSR_EL1 sys_reg(3, 0, 1, 0, 5)
+#define SYS_GCR_EL1 sys_reg(3, 0, 1, 0, 6)
#define SYS_ZCR_EL1 sys_reg(3, 0, 1, 2, 0)
@@ -209,6 +213,8 @@
#define SYS_ERXADDR_EL1 sys_reg(3, 0, 5, 4, 3)
#define SYS_ERXMISC0_EL1 sys_reg(3, 0, 5, 5, 0)
#define SYS_ERXMISC1_EL1 sys_reg(3, 0, 5, 5, 1)
+#define SYS_TFSR_EL1 sys_reg(3, 0, 5, 6, 0)
+#define SYS_TFSRE0_EL1 sys_reg(3, 0, 5, 6, 1)
#define SYS_FAR_EL1 sys_reg(3, 0, 6, 0, 0)
#define SYS_PAR_EL1 sys_reg(3, 0, 7, 4, 0)
@@ -359,6 +365,7 @@
#define SYS_CCSIDR_EL1 sys_reg(3, 1, 0, 0, 0)
#define SYS_CLIDR_EL1 sys_reg(3, 1, 0, 0, 1)
+#define SYS_GMID_EL1 sys_reg(3, 1, 0, 0, 4)
#define SYS_AIDR_EL1 sys_reg(3, 1, 0, 0, 7)
#define SYS_CSSELR_EL1 sys_reg(3, 2, 0, 0, 0)
@@ -415,6 +422,7 @@
#define SYS_ESR_EL2 sys_reg(3, 4, 5, 2, 0)
#define SYS_VSESR_EL2 sys_reg(3, 4, 5, 2, 3)
#define SYS_FPEXC32_EL2 sys_reg(3, 4, 5, 3, 0)
+#define SYS_TFSR_EL2 sys_reg(3, 4, 5, 6, 0)
#define SYS_FAR_EL2 sys_reg(3, 4, 6, 0, 0)
#define SYS_VDISR_EL2 sys_reg(3, 4, 12, 1, 1)
@@ -471,6 +479,7 @@
#define SYS_AFSR0_EL12 sys_reg(3, 5, 5, 1, 0)
#define SYS_AFSR1_EL12 sys_reg(3, 5, 5, 1, 1)
#define SYS_ESR_EL12 sys_reg(3, 5, 5, 2, 0)
+#define SYS_TFSR_EL12 sys_reg(3, 5, 5, 6, 0)
#define SYS_FAR_EL12 sys_reg(3, 5, 6, 0, 0)
#define SYS_MAIR_EL12 sys_reg(3, 5, 10, 2, 0)
#define SYS_AMAIR_EL12 sys_reg(3, 5, 10, 3, 0)
@@ -486,6 +495,15 @@
/* Common SCTLR_ELx flags. */
#define SCTLR_ELx_DSSBS (BIT(44))
+#define SCTLR_ELx_ATA (BIT(43))
+
+#define SCTLR_ELx_TCF_SHIFT 40
+#define SCTLR_ELx_TCF_NONE (UL(0x0) << SCTLR_ELx_TCF_SHIFT)
+#define SCTLR_ELx_TCF_SYNC (UL(0x1) << SCTLR_ELx_TCF_SHIFT)
+#define SCTLR_ELx_TCF_ASYNC (UL(0x2) << SCTLR_ELx_TCF_SHIFT)
+#define SCTLR_ELx_TCF_MASK (UL(0x3) << SCTLR_ELx_TCF_SHIFT)
+
+#define SCTLR_ELx_ITFSB (BIT(37))
#define SCTLR_ELx_ENIA (BIT(31))
#define SCTLR_ELx_ENIB (BIT(30))
#define SCTLR_ELx_ENDA (BIT(27))
@@ -514,6 +532,14 @@
#endif
/* SCTLR_EL1 specific flags. */
+#define SCTLR_EL1_ATA0 (BIT(42))
+
+#define SCTLR_EL1_TCF0_SHIFT 38
+#define SCTLR_EL1_TCF0_NONE (UL(0x0) << SCTLR_EL1_TCF0_SHIFT)
+#define SCTLR_EL1_TCF0_SYNC (UL(0x1) << SCTLR_EL1_TCF0_SHIFT)
+#define SCTLR_EL1_TCF0_ASYNC (UL(0x2) << SCTLR_EL1_TCF0_SHIFT)
+#define SCTLR_EL1_TCF0_MASK (UL(0x3) << SCTLR_EL1_TCF0_SHIFT)
+
#define SCTLR_EL1_UCI (BIT(26))
#define SCTLR_EL1_E0E (BIT(24))
#define SCTLR_EL1_SPAN (BIT(23))
@@ -548,6 +574,7 @@
#define MAIR_ATTR_DEVICE_GRE UL(0x0c)
#define MAIR_ATTR_NORMAL_NC UL(0x44)
#define MAIR_ATTR_NORMAL_WT UL(0xbb)
+#define MAIR_ATTR_NORMAL_TAGGED UL(0xf0)
#define MAIR_ATTR_NORMAL UL(0xff)
#define MAIR_ATTR_MASK UL(0xff)
@@ -620,11 +647,16 @@
/* id_aa64pfr1 */
#define ID_AA64PFR1_SSBS_SHIFT 4
+#define ID_AA64PFR1_MTE_SHIFT 8
#define ID_AA64PFR1_SSBS_PSTATE_NI 0
#define ID_AA64PFR1_SSBS_PSTATE_ONLY 1
#define ID_AA64PFR1_SSBS_PSTATE_INSNS 2
+#define ID_AA64PFR1_MTE_NI 0x0
+#define ID_AA64PFR1_MTE_EL0 0x1
+#define ID_AA64PFR1_MTE 0x2
+
/* id_aa64zfr0 */
#define ID_AA64ZFR0_F64MM_SHIFT 56
#define ID_AA64ZFR0_F32MM_SHIFT 52
@@ -772,6 +804,28 @@
#define CPACR_EL1_ZEN_EL0EN (BIT(17)) /* enable EL0 access, if EL1EN set */
#define CPACR_EL1_ZEN (CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN)
+/* TCR EL1 Bit Definitions */
+#define SYS_TCR_EL1_TCMA1 (BIT(58))
+#define SYS_TCR_EL1_TCMA0 (BIT(57))
+
+/* GCR_EL1 Definitions */
+#define SYS_GCR_EL1_RRND (BIT(16))
+#define SYS_GCR_EL1_EXCL_MASK 0xffffUL
+
+/* RGSR_EL1 Definitions */
+#define SYS_RGSR_EL1_TAG_MASK 0xfUL
+#define SYS_RGSR_EL1_SEED_SHIFT 8
+#define SYS_RGSR_EL1_SEED_MASK 0xffffUL
+
+/* GMID_EL1 field definitions */
+#define SYS_GMID_EL1_BS_SHIFT 0
+#define SYS_GMID_EL1_BS_SIZE 4
+
+/* TFSR{,E0}_EL1 bit definitions */
+#define SYS_TFSR_EL1_TF0_SHIFT 0
+#define SYS_TFSR_EL1_TF1_SHIFT 1
+#define SYS_TFSR_EL1_TF0 (UL(1) << SYS_TFSR_EL1_TF0_SHIFT)
+#define SYS_TFSR_EL1_TF1 (UK(2) << SYS_TFSR_EL1_TF1_SHIFT)
/* Safe value for MPIDR_EL1: Bit31:RES1, Bit30:U:0, Bit24:MT:0 */
#define SYS_MPIDR_SAFE_VAL (BIT(31))
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index d1bb5b69f1ce..1daf6dda8af0 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -50,6 +50,7 @@
#define PSR_PAN_BIT 0x00400000
#define PSR_UAO_BIT 0x00800000
#define PSR_DIT_BIT 0x01000000
+#define PSR_TCO_BIT 0x02000000
#define PSR_V_BIT 0x10000000
#define PSR_C_BIT 0x20000000
#define PSR_Z_BIT 0x40000000
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index cd6e5fa48b9c..72ee9f3b1fcc 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -1873,7 +1873,7 @@ void syscall_trace_exit(struct pt_regs *regs)
* We also reserve IL for the kernel; SS is handled dynamically.
*/
#define SPSR_EL1_AARCH64_RES0_BITS \
- (GENMASK_ULL(63, 32) | GENMASK_ULL(27, 25) | GENMASK_ULL(23, 22) | \
+ (GENMASK_ULL(63, 32) | GENMASK_ULL(27, 26) | GENMASK_ULL(23, 22) | \
GENMASK_ULL(20, 13) | GENMASK_ULL(11, 10) | GENMASK_ULL(5, 5))
#define SPSR_EL1_AARCH32_RES0_BITS \
(GENMASK_ULL(63, 32) | GENMASK_ULL(22, 22) | GENMASK_ULL(20, 20))
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 03/19] arm64: mte: CPU feature detection and initial sysreg configuration
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 01/19] arm64: alternative: Allow alternative_insn to always issue the first instruction Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 02/19] arm64: mte: system register definitions Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 04/19] arm64: mte: Use Normal Tagged attributes for the linear map Catalin Marinas
` (15 subsequent siblings)
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
From: Vincenzo Frascino <vincenzo.frascino@arm.com>
Add the cpufeature and hwcap entries to detect the presence of MTE on
the boot CPUs (primary and secondary). Any late secondary CPU not
supporting the feature, if detected during boot, will be parked.
In addition, add the minimum SCTLR_EL1 and HCR_EL2 bits for enabling
MTE. Without subsequent setting of MAIR, these bits do not have an
effect on tag checking.
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Co-developed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm64/include/asm/cpucaps.h | 4 +++-
arch/arm64/include/asm/cpufeature.h | 6 ++++++
arch/arm64/include/asm/hwcap.h | 1 +
arch/arm64/include/asm/kvm_arm.h | 2 +-
arch/arm64/include/asm/sysreg.h | 1 +
arch/arm64/include/uapi/asm/hwcap.h | 2 ++
arch/arm64/kernel/cpufeature.c | 30 +++++++++++++++++++++++++++++
arch/arm64/kernel/cpuinfo.c | 2 ++
8 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index 865e0253fc1e..cb54e42a5f5c 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -58,7 +58,9 @@
#define ARM64_WORKAROUND_SPECULATIVE_AT_NVHE 48
#define ARM64_HAS_E0PD 49
#define ARM64_HAS_RNG 50
+/* 51 reserved for ARM64_BTI */
+#define ARM64_MTE 52
-#define ARM64_NCAPS 51
+#define ARM64_NCAPS 53
#endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 92ef9539874a..80f73df8450e 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -607,6 +607,12 @@ static inline bool system_uses_irq_prio_masking(void)
cpus_have_const_cap(ARM64_HAS_IRQ_PRIO_MASKING);
}
+static inline bool system_supports_mte(void)
+{
+ return IS_ENABLED(CONFIG_ARM64_MTE) &&
+ cpus_have_const_cap(ARM64_MTE);
+}
+
static inline bool system_has_prio_mask_debugging(void)
{
return IS_ENABLED(CONFIG_ARM64_DEBUG_PRIORITY_MASKING) &&
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 0f00265248b5..8b302c88cfeb 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -94,6 +94,7 @@
#define KERNEL_HWCAP_BF16 __khwcap2_feature(BF16)
#define KERNEL_HWCAP_DGH __khwcap2_feature(DGH)
#define KERNEL_HWCAP_RNG __khwcap2_feature(RNG)
+#define KERNEL_HWCAP_MTE __khwcap2_feature(MTE)
/*
* This yields a mask that user programs can use to figure out what
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 0b25f9a81c57..37bcb93b376c 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -78,7 +78,7 @@
HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \
HCR_FMO | HCR_IMO)
#define HCR_VIRT_EXCP_MASK (HCR_VSE | HCR_VI | HCR_VF)
-#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK)
+#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK | HCR_ATA)
#define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
/* TCR_EL2 Registers bits */
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 9b95315c5c2a..13f0841b6ed3 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -566,6 +566,7 @@
SCTLR_EL1_SA0 | SCTLR_EL1_SED | SCTLR_ELx_I |\
SCTLR_EL1_DZE | SCTLR_EL1_UCT |\
SCTLR_EL1_NTWE | SCTLR_ELx_IESB | SCTLR_EL1_SPAN |\
+ SCTLR_ELx_ITFSB| SCTLR_ELx_ATA | SCTLR_EL1_ATA0 |\
ENDIAN_SET_EL1 | SCTLR_EL1_UCI | SCTLR_EL1_RES1)
/* MAIR_ELx memory attributes (used by Linux) */
diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
index 7752d93bb50f..73ac5aede18c 100644
--- a/arch/arm64/include/uapi/asm/hwcap.h
+++ b/arch/arm64/include/uapi/asm/hwcap.h
@@ -73,5 +73,7 @@
#define HWCAP2_BF16 (1 << 14)
#define HWCAP2_DGH (1 << 15)
#define HWCAP2_RNG (1 << 16)
+/* bit 17 reserved for HWCAP2_BTI */
+#define HWCAP2_MTE (1 << 18)
#endif /* _UAPI__ASM_HWCAP_H */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 0b6715625cf6..01e6e3a291fc 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -179,6 +179,8 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
static const struct arm64_ftr_bits ftr_id_aa64pfr1[] = {
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_SSBS_SHIFT, 4, ID_AA64PFR1_SSBS_PSTATE_NI),
+ ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_MTE),
+ FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_MTE_SHIFT, 4, ID_AA64PFR1_MTE_NI),
ARM64_FTR_END,
};
@@ -1347,6 +1349,18 @@ static bool can_use_gic_priorities(const struct arm64_cpu_capabilities *entry,
}
#endif
+#ifdef CONFIG_ARM64_MTE
+static void cpu_enable_mte(struct arm64_cpu_capabilities const *cap)
+{
+ /* all non-zero tags excluded by default */
+ write_sysreg_s(SYS_GCR_EL1_RRND | SYS_GCR_EL1_EXCL_MASK, SYS_GCR_EL1);
+ write_sysreg_s(0, SYS_TFSR_EL1);
+ write_sysreg_s(0, SYS_TFSRE0_EL1);
+
+ isb();
+}
+#endif /* CONFIG_ARM64_MTE */
+
static const struct arm64_cpu_capabilities arm64_features[] = {
{
.desc = "GIC system register CPU interface",
@@ -1672,6 +1686,19 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
.min_field_value = 1,
},
#endif
+#ifdef CONFIG_ARM64_MTE
+ {
+ .desc = "Memory Tagging Extension",
+ .capability = ARM64_MTE,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+ .matches = has_cpuid_feature,
+ .sys_reg = SYS_ID_AA64PFR1_EL1,
+ .field_pos = ID_AA64PFR1_MTE_SHIFT,
+ .min_field_value = ID_AA64PFR1_MTE,
+ .sign = FTR_UNSIGNED,
+ .cpu_enable = cpu_enable_mte,
+ },
+#endif /* CONFIG_ARM64_MTE */
{},
};
@@ -1785,6 +1812,9 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
HWCAP_MULTI_CAP(ptr_auth_hwcap_addr_matches, CAP_HWCAP, KERNEL_HWCAP_PACA),
HWCAP_MULTI_CAP(ptr_auth_hwcap_gen_matches, CAP_HWCAP, KERNEL_HWCAP_PACG),
#endif
+#ifdef CONFIG_ARM64_MTE
+ HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_MTE_SHIFT, FTR_UNSIGNED, ID_AA64PFR1_MTE, CAP_HWCAP, KERNEL_HWCAP_MTE),
+#endif /* CONFIG_ARM64_MTE */
{},
};
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 86136075ae41..d14b29de2c73 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -92,6 +92,8 @@ static const char *const hwcap_str[] = {
"bf16",
"dgh",
"rng",
+ "", /* reserved for BTI */
+ "mte",
NULL
};
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 04/19] arm64: mte: Use Normal Tagged attributes for the linear map
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (2 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 03/19] arm64: mte: CPU feature detection and initial sysreg configuration Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-03-05 16:21 ` Steven Price
2020-02-26 18:05 ` [PATCH v2 05/19] arm64: mte: Assembler macros and default architecture for .S files Catalin Marinas
` (14 subsequent siblings)
18 siblings, 1 reply; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
Once user space is given access to tagged memory, the kernel must be
able to clear/save/restore tags visible to the user. This is done via
the linear mapping, therefore map it as such. The new MT_NORMAL_TAGGED
index for MAIR_EL1 is initially mapped as Normal memory and later
changed to Normal Tagged via the cpufeature infrastructure. From a
mismatched attribute aliases perspective, the Tagged memory is
considered a permission and it won't lead to undefined behaviour.
The empty_zero_page is cleared to ensure that the tags it contains are
already zeroed. The actual tags-aware clear_page() implementation is
part of a subsequent patch.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm64/include/asm/memory.h | 1 +
arch/arm64/include/asm/pgtable-prot.h | 2 ++
arch/arm64/kernel/cpufeature.c | 30 +++++++++++++++++++++++++++
arch/arm64/mm/dump.c | 4 ++++
arch/arm64/mm/mmu.c | 22 ++++++++++++++++++--
arch/arm64/mm/proc.S | 8 +++++--
6 files changed, 63 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index a4f9ca5479b0..55994ab362ae 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -145,6 +145,7 @@
#define MT_NORMAL_NC 3
#define MT_NORMAL 4
#define MT_NORMAL_WT 5
+#define MT_NORMAL_TAGGED 6
/*
* Memory types for Stage-2 translation
diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 6f87839f0249..e5cc10ebfd23 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -37,6 +37,7 @@
#define PROT_NORMAL_NC (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC))
#define PROT_NORMAL_WT (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_WT))
#define PROT_NORMAL (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
+#define PROT_NORMAL_TAGGED (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_TAGGED))
#define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))
#define PROT_SECT_NORMAL (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
@@ -46,6 +47,7 @@
#define _HYP_PAGE_DEFAULT _PAGE_DEFAULT
#define PAGE_KERNEL __pgprot(PROT_NORMAL)
+#define PAGE_KERNEL_TAGGED __pgprot(PROT_NORMAL_TAGGED)
#define PAGE_KERNEL_RO __pgprot((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY)
#define PAGE_KERNEL_ROX __pgprot((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY)
#define PAGE_KERNEL_EXEC __pgprot(PROT_NORMAL & ~PTE_PXN)
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 01e6e3a291fc..87ed15670b09 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1352,13 +1352,43 @@ static bool can_use_gic_priorities(const struct arm64_cpu_capabilities *entry,
#ifdef CONFIG_ARM64_MTE
static void cpu_enable_mte(struct arm64_cpu_capabilities const *cap)
{
+ u64 mair;
+
/* all non-zero tags excluded by default */
write_sysreg_s(SYS_GCR_EL1_RRND | SYS_GCR_EL1_EXCL_MASK, SYS_GCR_EL1);
write_sysreg_s(0, SYS_TFSR_EL1);
write_sysreg_s(0, SYS_TFSRE0_EL1);
+ /*
+ * Update the MT_NORMAL_TAGGED index in MAIR_EL1. Tag checking is
+ * disabled for the kernel, so there won't be any observable effect
+ * other than allowing the kernel to read and write tags.
+ */
+ mair = read_sysreg_s(SYS_MAIR_EL1);
+ mair &= ~MAIR_ATTRIDX(MAIR_ATTR_MASK, MT_NORMAL_TAGGED);
+ mair |= MAIR_ATTRIDX(MAIR_ATTR_NORMAL_TAGGED, MT_NORMAL_TAGGED);
+ write_sysreg_s(mair, SYS_MAIR_EL1);
+
isb();
}
+
+static int __init system_enable_mte(void)
+{
+ if (!system_supports_mte())
+ return 0;
+
+ /* Ensure the TLB does not have stale MAIR attributes */
+ flush_tlb_all();
+
+ /*
+ * Clear the zero page (again) so that tags are reset. This needs to
+ * be done via the linear map which has the Tagged attribute.
+ */
+ clear_page(lm_alias(empty_zero_page));
+
+ return 0;
+}
+core_initcall(system_enable_mte);
#endif /* CONFIG_ARM64_MTE */
static const struct arm64_cpu_capabilities arm64_features[] = {
diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c
index 860c00ec8bd3..416a2404ac83 100644
--- a/arch/arm64/mm/dump.c
+++ b/arch/arm64/mm/dump.c
@@ -165,6 +165,10 @@ static const struct prot_bits pte_bits[] = {
.mask = PTE_ATTRINDX_MASK,
.val = PTE_ATTRINDX(MT_NORMAL),
.set = "MEM/NORMAL",
+ }, {
+ .mask = PTE_ATTRINDX_MASK,
+ .val = PTE_ATTRINDX(MT_NORMAL_TAGGED),
+ .set = "MEM/NORMAL-TAGGED",
}
};
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 128f70852bf3..a2c206444e47 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -120,7 +120,7 @@ static bool pgattr_change_is_safe(u64 old, u64 new)
* The following mapping attributes may be updated in live
* kernel mappings without the need for break-before-make.
*/
- static const pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE | PTE_NG;
+ pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE | PTE_NG;
/* creating or taking down mappings is always safe */
if (old == 0 || new == 0)
@@ -134,6 +134,19 @@ static bool pgattr_change_is_safe(u64 old, u64 new)
if (old & ~new & PTE_NG)
return false;
+ if (system_supports_mte()) {
+ /*
+ * Changing the memory type between Normal and Normal-Tagged
+ * is safe since Tagged is considered a permission attribute
+ * from the mismatched attribute aliases perspective.
+ */
+ if ((old & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL) ||
+ (old & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED) ||
+ (new & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL) ||
+ (new & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED))
+ mask |= PTE_ATTRINDX_MASK;
+ }
+
return ((old ^ new) & ~mask) == 0;
}
@@ -488,7 +501,12 @@ static void __init map_mem(pgd_t *pgdp)
if (memblock_is_nomap(reg))
continue;
- __map_memblock(pgdp, start, end, PAGE_KERNEL, flags);
+ /*
+ * The linear map must allow allocation tags reading/writing
+ * if MTE is present. Otherwise, it has the same attributes as
+ * PAGE_KERNEL.
+ */
+ __map_memblock(pgdp, start, end, PAGE_KERNEL_TAGGED, flags);
}
/*
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index aafed6902411..27dd81046af1 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -42,14 +42,18 @@
#define TCR_KASAN_FLAGS 0
#endif
-/* Default MAIR_EL1 */
+/*
+ * Default MAIR_EL1. MT_NORMAL_TAGGED is initially mapped as Normal memory and
+ * changed later to Normal Tagged if the system supports MTE.
+ */
#define MAIR_EL1_SET \
(MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRnE, MT_DEVICE_nGnRnE) | \
MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRE, MT_DEVICE_nGnRE) | \
MAIR_ATTRIDX(MAIR_ATTR_DEVICE_GRE, MT_DEVICE_GRE) | \
MAIR_ATTRIDX(MAIR_ATTR_NORMAL_NC, MT_NORMAL_NC) | \
MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL) | \
- MAIR_ATTRIDX(MAIR_ATTR_NORMAL_WT, MT_NORMAL_WT))
+ MAIR_ATTRIDX(MAIR_ATTR_NORMAL_WT, MT_NORMAL_WT) | \
+ MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL_TAGGED))
#ifdef CONFIG_CPU_PM
/**
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v2 04/19] arm64: mte: Use Normal Tagged attributes for the linear map
2020-02-26 18:05 ` [PATCH v2 04/19] arm64: mte: Use Normal Tagged attributes for the linear map Catalin Marinas
@ 2020-03-05 16:21 ` Steven Price
2020-03-05 16:38 ` Catalin Marinas
0 siblings, 1 reply; 32+ messages in thread
From: Steven Price @ 2020-03-05 16:21 UTC (permalink / raw)
To: Catalin Marinas, linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Will Deacon, Szabolcs Nagy,
Andrey Konovalov, Kevin Brodsky, linux-mm, Vincenzo Frascino,
Peter Collingbourne
On 26/02/2020 18:05, Catalin Marinas wrote:
> Once user space is given access to tagged memory, the kernel must be
> able to clear/save/restore tags visible to the user. This is done via
> the linear mapping, therefore map it as such. The new MT_NORMAL_TAGGED
> index for MAIR_EL1 is initially mapped as Normal memory and later
> changed to Normal Tagged via the cpufeature infrastructure. From a
> mismatched attribute aliases perspective, the Tagged memory is
> considered a permission and it won't lead to undefined behaviour.
>
> The empty_zero_page is cleared to ensure that the tags it contains are
> already zeroed. The actual tags-aware clear_page() implementation is
> part of a subsequent patch.
>
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> ---
> arch/arm64/include/asm/memory.h | 1 +
> arch/arm64/include/asm/pgtable-prot.h | 2 ++
> arch/arm64/kernel/cpufeature.c | 30 +++++++++++++++++++++++++++
> arch/arm64/mm/dump.c | 4 ++++
> arch/arm64/mm/mmu.c | 22 ++++++++++++++++++--
> arch/arm64/mm/proc.S | 8 +++++--
> 6 files changed, 63 insertions(+), 4 deletions(-)
>
[...]
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 128f70852bf3..a2c206444e47 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -120,7 +120,7 @@ static bool pgattr_change_is_safe(u64 old, u64 new)
> * The following mapping attributes may be updated in live
> * kernel mappings without the need for break-before-make.
> */
> - static const pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE | PTE_NG;
> + pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE | PTE_NG;
>
> /* creating or taking down mappings is always safe */
> if (old == 0 || new == 0)
> @@ -134,6 +134,19 @@ static bool pgattr_change_is_safe(u64 old, u64 new)
> if (old & ~new & PTE_NG)
> return false;
>
> + if (system_supports_mte()) {
> + /*
> + * Changing the memory type between Normal and Normal-Tagged
> + * is safe since Tagged is considered a permission attribute
> + * from the mismatched attribute aliases perspective.
> + */
> + if ((old & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL) ||
> + (old & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED) ||
> + (new & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL) ||
> + (new & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED))
> + mask |= PTE_ATTRINDX_MASK;
> + }
> +
> return ((old ^ new) & ~mask) == 0;
> }
This is much more permissive than I would expect. If either the old or
new memory type is NORMAL (or NORMAL_TAGGED) then the memory type is
ignored altogether.
Should this check be:
if (((old & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL) ||
(old & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED)) &&
((new & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL) ||
(new & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED)))
Steve
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 04/19] arm64: mte: Use Normal Tagged attributes for the linear map
2020-03-05 16:21 ` Steven Price
@ 2020-03-05 16:38 ` Catalin Marinas
0 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-03-05 16:38 UTC (permalink / raw)
To: Steven Price
Cc: linux-arch, Richard Earnshaw, Will Deacon, Szabolcs Nagy,
Andrey Konovalov, Kevin Brodsky, linux-mm, Vincenzo Frascino,
Peter Collingbourne, linux-arm-kernel
On Thu, Mar 05, 2020 at 04:21:34PM +0000, Steven Price wrote:
> On 26/02/2020 18:05, Catalin Marinas wrote:
> > + if (system_supports_mte()) {
> > + /*
> > + * Changing the memory type between Normal and Normal-Tagged
> > + * is safe since Tagged is considered a permission attribute
> > + * from the mismatched attribute aliases perspective.
> > + */
> > + if ((old & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL) ||
> > + (old & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED) ||
> > + (new & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL) ||
> > + (new & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED))
> > + mask |= PTE_ATTRINDX_MASK;
> > + }
> > +
> > return ((old ^ new) & ~mask) == 0;
> > }
>
> This is much more permissive than I would expect. If either the old or
> new memory type is NORMAL (or NORMAL_TAGGED) then the memory type is
> ignored altogether.
>
> Should this check be:
>
> if (((old & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL) ||
> (old & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED)) &&
> ((new & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL) ||
> (new & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED)))
You are right, I think my patch allows many other memory type
combinations. Thanks.
--
Catalin
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 05/19] arm64: mte: Assembler macros and default architecture for .S files
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (3 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 04/19] arm64: mte: Use Normal Tagged attributes for the linear map Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 06/19] arm64: mte: Tags-aware clear_page() implementation Catalin Marinas
` (13 subsequent siblings)
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
Add the multitag_transfer_size macro to the arm64 assembler.h, together
with '.arch armv8.5-a+memtag' when CONFIG_ARM64_MTE is enabled.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
Notes:
v2:
- Separate .arch armv8.5-a from .arch_extension memtag.
arch/arm64/include/asm/assembler.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index aca337d79d12..172d114ba8a8 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -21,8 +21,14 @@
#include <asm/page.h>
#include <asm/pgtable-hwdef.h>
#include <asm/ptrace.h>
+#include <asm/sysreg.h>
#include <asm/thread_info.h>
+#ifdef CONFIG_ARM64_MTE
+ .arch armv8.5-a
+ .arch_extension memtag
+#endif
+
.macro save_and_disable_daif, flags
mrs \flags, daif
msr daifset, #0xf
@@ -732,4 +738,15 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU
.Lyield_out_\@ :
.endm
+/*
+ * multitag_transfer_size - set \reg to the block size that is accessed by the
+ * LDGM/STGM instructions.
+ */
+ .macro multitag_transfer_size, reg, tmp
+ mrs_s \reg, SYS_GMID_EL1
+ ubfx \reg, \reg, #SYS_GMID_EL1_BS_SHIFT, #SYS_GMID_EL1_BS_SIZE
+ mov \tmp, #4
+ lsl \reg, \tmp, \reg
+ .endm
+
#endif /* __ASM_ASSEMBLER_H */
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 06/19] arm64: mte: Tags-aware clear_page() implementation
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (4 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 05/19] arm64: mte: Assembler macros and default architecture for .S files Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 07/19] arm64: mte: Tags-aware copy_page() implementation Catalin Marinas
` (12 subsequent siblings)
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
From: Vincenzo Frascino <vincenzo.frascino@arm.com>
When the Memory Tagging Extension is enabled, the tags need to be set to
zero a page is cleared as they are visible to the user.
Introduce an MTE-aware clear_page() which clears the tags in addition to
data.
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Co-developed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm64/lib/clear_page.S | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/lib/clear_page.S b/arch/arm64/lib/clear_page.S
index 073acbf02a7c..9f85a4cf9568 100644
--- a/arch/arm64/lib/clear_page.S
+++ b/arch/arm64/lib/clear_page.S
@@ -5,7 +5,9 @@
#include <linux/linkage.h>
#include <linux/const.h>
+#include <asm/alternative.h>
#include <asm/assembler.h>
+#include <asm/cpufeature.h>
#include <asm/page.h>
/*
@@ -19,8 +21,9 @@ SYM_FUNC_START(clear_page)
and w1, w1, #0xf
mov x2, #4
lsl x1, x2, x1
-
-1: dc zva, x0
+1:
+alternative_insn "dc zva, x0", "stzgm xzr, [x0]", \
+ ARM64_MTE, IS_ENABLED(CONFIG_ARM64_MTE), 1
add x0, x0, x1
tst x0, #(PAGE_SIZE - 1)
b.ne 1b
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 07/19] arm64: mte: Tags-aware copy_page() implementation
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (5 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 06/19] arm64: mte: Tags-aware clear_page() implementation Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 08/19] arm64: Tags-aware memcmp_pages() implementation Catalin Marinas
` (11 subsequent siblings)
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
From: Vincenzo Frascino <vincenzo.frascino@arm.com>
When the Memory Tagging Extension is enabled, the tags need to be
preserved across page copy (e.g. for copy-on-write).
Introduce MTE-aware copy_page() which preserves the tags across page
copy.
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Co-developed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm64/lib/copy_page.S | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/arch/arm64/lib/copy_page.S b/arch/arm64/lib/copy_page.S
index e7a793961408..c3234175efe0 100644
--- a/arch/arm64/lib/copy_page.S
+++ b/arch/arm64/lib/copy_page.S
@@ -25,6 +25,29 @@ alternative_if ARM64_HAS_NO_HW_PREFETCH
prfm pldl1strm, [x1, #384]
alternative_else_nop_endif
+#ifdef CONFIG_ARM64_MTE
+alternative_if_not ARM64_MTE
+ b 2f
+alternative_else_nop_endif
+ /*
+ * Copy tags if MTE has been enabled.
+ */
+ mov x2, x0
+ mov x3, x1
+
+ multitag_transfer_size x7, x5
+1:
+ ldgm x4, [x3]
+ stgm x4, [x2]
+
+ add x2, x2, x7
+ add x3, x3, x7
+
+ tst x2, #(PAGE_SIZE - 1)
+ b.ne 1b
+2:
+#endif
+
ldp x2, x3, [x1]
ldp x4, x5, [x1, #16]
ldp x6, x7, [x1, #32]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 08/19] arm64: Tags-aware memcmp_pages() implementation
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (6 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 07/19] arm64: mte: Tags-aware copy_page() implementation Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 09/19] arm64: mte: Add specific SIGSEGV codes Catalin Marinas
` (10 subsequent siblings)
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
When the Memory Tagging Extension is enabled, two pages are identical
only if both their data and tags are identical.
Make the generic memcmp_pages() a __weak function and add an
arm64-specific implementation which takes care of the tags comparison.
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>
---
arch/arm64/include/asm/mte.h | 11 +++++++++
arch/arm64/lib/Makefile | 2 ++
arch/arm64/lib/mte.S | 46 ++++++++++++++++++++++++++++++++++++
arch/arm64/mm/Makefile | 1 +
arch/arm64/mm/cmppages.c | 26 ++++++++++++++++++++
mm/util.c | 2 +-
6 files changed, 87 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/include/asm/mte.h
create mode 100644 arch/arm64/lib/mte.S
create mode 100644 arch/arm64/mm/cmppages.c
diff --git a/arch/arm64/include/asm/mte.h b/arch/arm64/include/asm/mte.h
new file mode 100644
index 000000000000..64e814273659
--- /dev/null
+++ b/arch/arm64/include/asm/mte.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_MTE_H
+#define __ASM_MTE_H
+
+#ifndef __ASSEMBLY__
+
+/* Memory Tagging API */
+int mte_memcmp_pages(const void *page1_addr, const void *page2_addr);
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_MTE_H */
diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile
index 2fc253466dbf..d31e1169d9b8 100644
--- a/arch/arm64/lib/Makefile
+++ b/arch/arm64/lib/Makefile
@@ -16,3 +16,5 @@ lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o
obj-$(CONFIG_CRC32) += crc32.o
obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
+
+obj-$(CONFIG_ARM64_MTE) += mte.o
diff --git a/arch/arm64/lib/mte.S b/arch/arm64/lib/mte.S
new file mode 100644
index 000000000000..d41955ab4134
--- /dev/null
+++ b/arch/arm64/lib/mte.S
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2019 ARM Ltd.
+ */
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+
+/*
+ * Compare tags of two pages
+ * x0 - page1 address
+ * x1 - page2 address
+ * Returns:
+ * w0 - negative, zero or positive value if the tag in the first page is
+ * less than, equal to or greater than the tag in the second page
+ */
+ENTRY(mte_memcmp_pages)
+ multitag_transfer_size x7, x5
+1:
+ ldgm x2, [x0]
+ ldgm x3, [x1]
+
+ eor x4, x2, x3
+ cbnz x4, 2f
+
+ add x0, x0, x7
+ add x1, x1, x7
+
+ tst x0, #(PAGE_SIZE - 1)
+ b.ne 1b
+
+ mov w0, #0
+ ret
+2:
+ rbit x4, x4
+ clz x4, x4 // count the least significant equal bits
+ and x4, x4, #~3 // round down to a multiple of 4 (bits per tag)
+
+ lsr x2, x2, x4 // remove equal tags
+ lsr x3, x3, x4
+
+ lsl w2, w2, #28 // compare the differing tags
+ sub w0, w2, w3, lsl #28
+
+ ret
+ENDPROC(mte_memcmp_pages)
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
index d91030f0ffee..e93d696295d0 100644
--- a/arch/arm64/mm/Makefile
+++ b/arch/arm64/mm/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PTDUMP_CORE) += dump.o
obj-$(CONFIG_PTDUMP_DEBUGFS) += ptdump_debugfs.o
obj-$(CONFIG_NUMA) += numa.o
obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o
+obj-$(CONFIG_ARM64_MTE) += cmppages.o
KASAN_SANITIZE_physaddr.o += n
obj-$(CONFIG_KASAN) += kasan_init.o
diff --git a/arch/arm64/mm/cmppages.c b/arch/arm64/mm/cmppages.c
new file mode 100644
index 000000000000..943c1877e014
--- /dev/null
+++ b/arch/arm64/mm/cmppages.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2019 ARM Ltd.
+ */
+
+#include <linux/mm.h>
+#include <linux/string.h>
+
+#include <asm/cpufeature.h>
+#include <asm/mte.h>
+
+int memcmp_pages(struct page *page1, struct page *page2)
+{
+ char *addr1, *addr2;
+ int ret;
+
+ addr1 = page_address(page1);
+ addr2 = page_address(page2);
+
+ ret = memcmp(addr1, addr2, PAGE_SIZE);
+ /* if page content identical, check the tags */
+ if (ret == 0 && system_supports_mte())
+ ret = mte_memcmp_pages(addr1, addr2);
+
+ return ret;
+}
diff --git a/mm/util.c b/mm/util.c
index 988d11e6c17c..662fb3da6d01 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -899,7 +899,7 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen)
return res;
}
-int memcmp_pages(struct page *page1, struct page *page2)
+int __weak memcmp_pages(struct page *page1, struct page *page2)
{
char *addr1, *addr2;
int ret;
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 09/19] arm64: mte: Add specific SIGSEGV codes
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (7 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 08/19] arm64: Tags-aware memcmp_pages() implementation Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 19:05 ` Eric W. Biederman
2020-02-26 22:33 ` kbuild test robot
2020-02-26 18:05 ` [PATCH v2 10/19] arm64: mte: Handle synchronous and asynchronous tag check faults Catalin Marinas
` (9 subsequent siblings)
18 siblings, 2 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Arnd Bergmann, Szabolcs Nagy,
Andrey Konovalov, Kevin Brodsky, Peter Collingbourne, linux-mm,
Eric W. Biederman, Vincenzo Frascino, Will Deacon
From: Vincenzo Frascino <vincenzo.frascino@arm.com>
Add MTE-specific SIGSEGV codes to siginfo.h.
Note that the for MTE we are reusing the same SPARC ADI codes because
the two functionalities are similar and they cannot coexist on the same
system.
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
[catalin.marinas@arm.com: renamed precise/imprecise to sync/async]
[catalin.marinas@arm.com: dropped #ifdef __aarch64__, renumbered]
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
Notes:
v2:
- Dropped the #ifdef __aarch64__.
- Renumbered the SEGV_MTE* values to avoid clash with ADI.
include/uapi/asm-generic/siginfo.h | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index cb3d6c267181..7aacf9389010 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -229,7 +229,9 @@ typedef struct siginfo {
#define SEGV_ACCADI 5 /* ADI not enabled for mapped object */
#define SEGV_ADIDERR 6 /* Disrupting MCD error */
#define SEGV_ADIPERR 7 /* Precise MCD exception */
-#define NSIGSEGV 7
+#define SEGV_MTEAERR 8 /* Asynchronous ARM MTE error */
+#define SEGV_MTESERR 9 /* Synchronous ARM MTE exception */
+#define NSIGSEGV 9
/*
* SIGBUS si_codes
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v2 09/19] arm64: mte: Add specific SIGSEGV codes
2020-02-26 18:05 ` [PATCH v2 09/19] arm64: mte: Add specific SIGSEGV codes Catalin Marinas
@ 2020-02-26 19:05 ` Eric W. Biederman
2020-02-26 19:26 ` Catalin Marinas
2020-02-26 22:33 ` kbuild test robot
1 sibling, 1 reply; 32+ messages in thread
From: Eric W. Biederman @ 2020-02-26 19:05 UTC (permalink / raw)
To: Catalin Marinas
Cc: linux-arch, Richard Earnshaw, Arnd Bergmann, Szabolcs Nagy,
Andrey Konovalov, Kevin Brodsky, Peter Collingbourne, linux-mm,
Vincenzo Frascino, Will Deacon, linux-arm-kernel
Catalin Marinas <catalin.marinas@arm.com> writes:
> From: Vincenzo Frascino <vincenzo.frascino@arm.com>
>
> Add MTE-specific SIGSEGV codes to siginfo.h.
>
> Note that the for MTE we are reusing the same SPARC ADI codes because
> the two functionalities are similar and they cannot coexist on the same
> system.
Any chance you can move the v2 notes up into the description or
otherwise fix it. The description talks about reusing the ADI codes
which is no longer happening.
Otherwise the patch looks good.
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Eric W. Biederman <ebiederm@xmission.com>
> Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
> [catalin.marinas@arm.com: renamed precise/imprecise to sync/async]
> [catalin.marinas@arm.com: dropped #ifdef __aarch64__, renumbered]
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> ---
>
> Notes:
> v2:
> - Dropped the #ifdef __aarch64__.
> - Renumbered the SEGV_MTE* values to avoid clash with ADI.
>
> include/uapi/asm-generic/siginfo.h | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
> index cb3d6c267181..7aacf9389010 100644
> --- a/include/uapi/asm-generic/siginfo.h
> +++ b/include/uapi/asm-generic/siginfo.h
> @@ -229,7 +229,9 @@ typedef struct siginfo {
> #define SEGV_ACCADI 5 /* ADI not enabled for mapped object */
> #define SEGV_ADIDERR 6 /* Disrupting MCD error */
> #define SEGV_ADIPERR 7 /* Precise MCD exception */
> -#define NSIGSEGV 7
> +#define SEGV_MTEAERR 8 /* Asynchronous ARM MTE error */
> +#define SEGV_MTESERR 9 /* Synchronous ARM MTE exception */
> +#define NSIGSEGV 9
>
> /*
> * SIGBUS si_codes
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 09/19] arm64: mte: Add specific SIGSEGV codes
2020-02-26 19:05 ` Eric W. Biederman
@ 2020-02-26 19:26 ` Catalin Marinas
0 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 19:26 UTC (permalink / raw)
To: Eric W. Biederman
Cc: linux-arch, Richard Earnshaw, Arnd Bergmann, Szabolcs Nagy,
Andrey Konovalov, Kevin Brodsky, Peter Collingbourne, linux-mm,
Vincenzo Frascino, Will Deacon, linux-arm-kernel
On Wed, Feb 26, 2020 at 01:05:52PM -0600, Eric W. Biederman wrote:
> Catalin Marinas <catalin.marinas@arm.com> writes:
>
> > From: Vincenzo Frascino <vincenzo.frascino@arm.com>
> >
> > Add MTE-specific SIGSEGV codes to siginfo.h.
> >
> > Note that the for MTE we are reusing the same SPARC ADI codes because
> > the two functionalities are similar and they cannot coexist on the same
> > system.
>
> Any chance you can move the v2 notes up into the description or
> otherwise fix it. The description talks about reusing the ADI codes
> which is no longer happening.
Oh, I forgot to check the patch description. I will fix it.
> Otherwise the patch looks good.
>
> Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Thanks.
--
Catalin
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 09/19] arm64: mte: Add specific SIGSEGV codes
2020-02-26 18:05 ` [PATCH v2 09/19] arm64: mte: Add specific SIGSEGV codes Catalin Marinas
2020-02-26 19:05 ` Eric W. Biederman
@ 2020-02-26 22:33 ` kbuild test robot
2020-02-27 11:05 ` Catalin Marinas
1 sibling, 1 reply; 32+ messages in thread
From: kbuild test robot @ 2020-02-26 22:33 UTC (permalink / raw)
To: Catalin Marinas
Cc: linux-arch, Richard Earnshaw, kbuild-all, Arnd Bergmann,
Szabolcs Nagy, Andrey Konovalov, Kevin Brodsky,
Peter Collingbourne, linux-mm, Eric W. Biederman,
Vincenzo Frascino, Will Deacon, linux-arm-kernel
[-- Attachment #1: Type: text/plain, Size: 6064 bytes --]
Hi Catalin,
I love your patch! Yet something to improve:
[auto build test ERROR on arm-soc/for-next]
[also build test ERROR on arm/for-next linus/master v5.6-rc3 next-20200226]
[cannot apply to arm64/for-next/core kvmarm/next xlnx/master arm-perf/for-next/perf]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Catalin-Marinas/arm64-Memory-Tagging-Extension-user-space-support/20200227-041230
base: https://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git for-next
config: x86_64-defconfig (attached as .config)
compiler: gcc-7 (Debian 7.5.0-5) 7.5.0
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>
All error/warnings (new ones prefixed by >>):
In file included from include/linux/export.h:43:0,
from include/linux/linkage.h:7,
from arch/x86/include/asm/cache.h:5,
from include/linux/cache.h:6,
from include/linux/time.h:5,
from include/linux/compat.h:10,
from arch/x86/kernel/signal_compat.c:2:
In function 'signal_compat_build_tests',
inlined from 'sigaction_compat_abi' at arch/x86/kernel/signal_compat.c:166:2:
>> include/linux/compiler.h:350:38: error: call to '__compiletime_assert_30' declared with attribute error: BUILD_BUG_ON failed: NSIGSEGV != 7
_compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)
^
include/linux/compiler.h:331:4: note: in definition of macro '__compiletime_assert'
prefix ## suffix(); \
^~~~~~
include/linux/compiler.h:350:2: note: in expansion of macro '_compiletime_assert'
_compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)
^~~~~~~~~~~~~~~~~~~
include/linux/build_bug.h:39:37: note: in expansion of macro 'compiletime_assert'
#define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
^~~~~~~~~~~~~~~~~~
include/linux/build_bug.h:50:2: note: in expansion of macro 'BUILD_BUG_ON_MSG'
BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
^~~~~~~~~~~~~~~~
>> arch/x86/kernel/signal_compat.c:30:2: note: in expansion of macro 'BUILD_BUG_ON'
BUILD_BUG_ON(NSIGSEGV != 7);
^~~~~~~~~~~~
--
In file included from include/linux/export.h:43:0,
from include/linux/linkage.h:7,
from arch/x86/include/asm/cache.h:5,
from include/linux/cache.h:6,
from include/linux/time.h:5,
from include/linux/compat.h:10,
from arch/x86//kernel/signal_compat.c:2:
In function 'signal_compat_build_tests',
inlined from 'sigaction_compat_abi' at arch/x86//kernel/signal_compat.c:166:2:
>> include/linux/compiler.h:350:38: error: call to '__compiletime_assert_30' declared with attribute error: BUILD_BUG_ON failed: NSIGSEGV != 7
_compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)
^
include/linux/compiler.h:331:4: note: in definition of macro '__compiletime_assert'
prefix ## suffix(); \
^~~~~~
include/linux/compiler.h:350:2: note: in expansion of macro '_compiletime_assert'
_compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)
^~~~~~~~~~~~~~~~~~~
include/linux/build_bug.h:39:37: note: in expansion of macro 'compiletime_assert'
#define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
^~~~~~~~~~~~~~~~~~
include/linux/build_bug.h:50:2: note: in expansion of macro 'BUILD_BUG_ON_MSG'
BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
^~~~~~~~~~~~~~~~
arch/x86//kernel/signal_compat.c:30:2: note: in expansion of macro 'BUILD_BUG_ON'
BUILD_BUG_ON(NSIGSEGV != 7);
^~~~~~~~~~~~
vim +/__compiletime_assert_30 +350 include/linux/compiler.h
9a8ab1c39970a4 Daniel Santos 2013-02-21 336
9a8ab1c39970a4 Daniel Santos 2013-02-21 337 #define _compiletime_assert(condition, msg, prefix, suffix) \
9a8ab1c39970a4 Daniel Santos 2013-02-21 338 __compiletime_assert(condition, msg, prefix, suffix)
9a8ab1c39970a4 Daniel Santos 2013-02-21 339
9a8ab1c39970a4 Daniel Santos 2013-02-21 340 /**
9a8ab1c39970a4 Daniel Santos 2013-02-21 341 * compiletime_assert - break build and emit msg if condition is false
9a8ab1c39970a4 Daniel Santos 2013-02-21 342 * @condition: a compile-time constant condition to check
9a8ab1c39970a4 Daniel Santos 2013-02-21 343 * @msg: a message to emit if condition is false
9a8ab1c39970a4 Daniel Santos 2013-02-21 344 *
9a8ab1c39970a4 Daniel Santos 2013-02-21 345 * In tradition of POSIX assert, this macro will break the build if the
9a8ab1c39970a4 Daniel Santos 2013-02-21 346 * supplied condition is *false*, emitting the supplied error message if the
9a8ab1c39970a4 Daniel Santos 2013-02-21 347 * compiler has support to do so.
9a8ab1c39970a4 Daniel Santos 2013-02-21 348 */
9a8ab1c39970a4 Daniel Santos 2013-02-21 349 #define compiletime_assert(condition, msg) \
9a8ab1c39970a4 Daniel Santos 2013-02-21 @350 _compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)
9a8ab1c39970a4 Daniel Santos 2013-02-21 351
:::::: The code at line 350 was first introduced by commit
:::::: 9a8ab1c39970a4938a72d94e6fd13be88a797590 bug.h, compiler.h: introduce compiletime_assert & BUILD_BUG_ON_MSG
:::::: TO: Daniel Santos <daniel.santos@pobox.com>
:::::: CC: Linus Torvalds <torvalds@linux-foundation.org>
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 29018 bytes --]
[-- Attachment #3: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 09/19] arm64: mte: Add specific SIGSEGV codes
2020-02-26 22:33 ` kbuild test robot
@ 2020-02-27 11:05 ` Catalin Marinas
2020-02-27 15:20 ` Eric W. Biederman
0 siblings, 1 reply; 32+ messages in thread
From: Catalin Marinas @ 2020-02-27 11:05 UTC (permalink / raw)
To: kbuild test robot
Cc: linux-arch, Richard Earnshaw, kbuild-all, Arnd Bergmann,
Szabolcs Nagy, Andrey Konovalov, Kevin Brodsky,
Peter Collingbourne, linux-mm, Eric W. Biederman,
Vincenzo Frascino, Will Deacon, linux-arm-kernel
On Thu, Feb 27, 2020 at 06:33:14AM +0800, kbuild test robot wrote:
> url: https://github.com/0day-ci/linux/commits/Catalin-Marinas/arm64-Memory-Tagging-Extension-user-space-support/20200227-041230
> base: https://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git for-next
> config: x86_64-defconfig (attached as .config)
> compiler: gcc-7 (Debian 7.5.0-5) 7.5.0
> reproduce:
> # save the attached .config to linux build tree
> make ARCH=x86_64
>
> If you fix the issue, kindly add following tag
> Reported-by: kbuild test robot <lkp@intel.com>
>
> All error/warnings (new ones prefixed by >>):
>
> In file included from include/linux/export.h:43:0,
> from include/linux/linkage.h:7,
> from arch/x86/include/asm/cache.h:5,
> from include/linux/cache.h:6,
> from include/linux/time.h:5,
> from include/linux/compat.h:10,
> from arch/x86/kernel/signal_compat.c:2:
> In function 'signal_compat_build_tests',
> inlined from 'sigaction_compat_abi' at arch/x86/kernel/signal_compat.c:166:2:
> >> include/linux/compiler.h:350:38: error: call to '__compiletime_assert_30' declared with attribute error: BUILD_BUG_ON failed: NSIGSEGV != 7
I haven't realised that x86 has a build check for NSIGSEGV. I'll fold in
the diff below (there are no new fields added to siginfo, so no other
changes necessary):
diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c
index 9ccbf0576cd0..a7f3e12cfbdb 100644
--- a/arch/x86/kernel/signal_compat.c
+++ b/arch/x86/kernel/signal_compat.c
@@ -27,7 +27,7 @@ static inline void signal_compat_build_tests(void)
*/
BUILD_BUG_ON(NSIGILL != 11);
BUILD_BUG_ON(NSIGFPE != 15);
- BUILD_BUG_ON(NSIGSEGV != 7);
+ BUILD_BUG_ON(NSIGSEGV != 9);
BUILD_BUG_ON(NSIGBUS != 5);
BUILD_BUG_ON(NSIGTRAP != 5);
BUILD_BUG_ON(NSIGCHLD != 6);
--
Catalin
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v2 09/19] arm64: mte: Add specific SIGSEGV codes
2020-02-27 11:05 ` Catalin Marinas
@ 2020-02-27 15:20 ` Eric W. Biederman
0 siblings, 0 replies; 32+ messages in thread
From: Eric W. Biederman @ 2020-02-27 15:20 UTC (permalink / raw)
To: Catalin Marinas
Cc: linux-arch, Richard Earnshaw, kbuild-all, kbuild test robot,
Arnd Bergmann, Szabolcs Nagy, Andrey Konovalov, Kevin Brodsky,
Peter Collingbourne, linux-mm, Vincenzo Frascino, Will Deacon,
linux-arm-kernel
Catalin Marinas <catalin.marinas@arm.com> writes:
> On Thu, Feb 27, 2020 at 06:33:14AM +0800, kbuild test robot wrote:
>> url: https://github.com/0day-ci/linux/commits/Catalin-Marinas/arm64-Memory-Tagging-Extension-user-space-support/20200227-041230
>> base: https://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git for-next
>> config: x86_64-defconfig (attached as .config)
>> compiler: gcc-7 (Debian 7.5.0-5) 7.5.0
>> reproduce:
>> # save the attached .config to linux build tree
>> make ARCH=x86_64
>>
>> If you fix the issue, kindly add following tag
>> Reported-by: kbuild test robot <lkp@intel.com>
>>
>> All error/warnings (new ones prefixed by >>):
>>
>> In file included from include/linux/export.h:43:0,
>> from include/linux/linkage.h:7,
>> from arch/x86/include/asm/cache.h:5,
>> from include/linux/cache.h:6,
>> from include/linux/time.h:5,
>> from include/linux/compat.h:10,
>> from arch/x86/kernel/signal_compat.c:2:
>> In function 'signal_compat_build_tests',
>> inlined from 'sigaction_compat_abi' at arch/x86/kernel/signal_compat.c:166:2:
>> >> include/linux/compiler.h:350:38: error: call to '__compiletime_assert_30' declared with attribute error: BUILD_BUG_ON failed: NSIGSEGV != 7
>
> I haven't realised that x86 has a build check for NSIGSEGV. I'll fold in
> the diff below (there are no new fields added to siginfo, so no other
> changes necessary):
Yes. That looks good.
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
> diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c
> index 9ccbf0576cd0..a7f3e12cfbdb 100644
> --- a/arch/x86/kernel/signal_compat.c
> +++ b/arch/x86/kernel/signal_compat.c
> @@ -27,7 +27,7 @@ static inline void signal_compat_build_tests(void)
> */
> BUILD_BUG_ON(NSIGILL != 11);
> BUILD_BUG_ON(NSIGFPE != 15);
> - BUILD_BUG_ON(NSIGSEGV != 7);
> + BUILD_BUG_ON(NSIGSEGV != 9);
> BUILD_BUG_ON(NSIGBUS != 5);
> BUILD_BUG_ON(NSIGTRAP != 5);
> BUILD_BUG_ON(NSIGCHLD != 6);
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 10/19] arm64: mte: Handle synchronous and asynchronous tag check faults
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (8 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 09/19] arm64: mte: Add specific SIGSEGV codes Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-27 11:50 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 11/19] mm: Introduce arch_calc_vm_flag_bits() Catalin Marinas
` (8 subsequent siblings)
18 siblings, 1 reply; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
From: Vincenzo Frascino <vincenzo.frascino@arm.com>
The Memory Tagging Extension has two modes of notifying a tag check
fault at EL0, configurable through the SCTLR_EL1.TCF0 field:
1. Synchronous raising of a Data Abort exception with DFSC 17.
2. Asynchronous setting of a cumulative bit in TFSRE0_EL1.
Add the exception handler for the synchronous exception and handling of
the asynchronous TFSRE0_EL1.TF0 bit setting via a new TIF flag in
do_notify_resume().
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Co-developed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
Notes:
v2:
- Clear PSTATE.TCO on exception entry (automatically set by the hardware).
- On syscall entry, for asynchronous tag check faults from user space,
generate the signal early via syscall restarting.
- Before context switch, save any potential async tag check fault
generated by the kernel to the TIF flag (this follows an architecture
update where the uaccess routines use the TCF0 mode).
- Moved the flush_mte_state() and mte_thread_switch() function to a new
mte.c file.
arch/arm64/include/asm/mte.h | 14 +++++++++++
arch/arm64/include/asm/thread_info.h | 4 ++-
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/entry.S | 27 ++++++++++++++++++++
arch/arm64/kernel/mte.c | 37 ++++++++++++++++++++++++++++
arch/arm64/kernel/process.c | 3 +++
arch/arm64/kernel/signal.c | 8 ++++++
arch/arm64/kernel/syscall.c | 10 ++++++++
arch/arm64/mm/fault.c | 9 ++++++-
9 files changed, 111 insertions(+), 2 deletions(-)
create mode 100644 arch/arm64/kernel/mte.c
diff --git a/arch/arm64/include/asm/mte.h b/arch/arm64/include/asm/mte.h
index 64e814273659..0d7f7ca07ee6 100644
--- a/arch/arm64/include/asm/mte.h
+++ b/arch/arm64/include/asm/mte.h
@@ -4,8 +4,22 @@
#ifndef __ASSEMBLY__
+#include <linux/sched.h>
+
/* Memory Tagging API */
int mte_memcmp_pages(const void *page1_addr, const void *page2_addr);
+#ifdef CONFIG_ARM64_MTE
+void flush_mte_state(void);
+void mte_thread_switch(struct task_struct *next);
+#else
+static inline void flush_mte_state(void)
+{
+}
+static inline void mte_thread_switch(struct task_struct *next)
+{
+}
+#endif
+
#endif /* __ASSEMBLY__ */
#endif /* __ASM_MTE_H */
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index f0cec4160136..f759a0215a71 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -63,6 +63,7 @@ void arch_release_task_struct(struct task_struct *tsk);
#define TIF_FOREIGN_FPSTATE 3 /* CPU's FP state is not current's */
#define TIF_UPROBE 4 /* uprobe breakpoint or singlestep */
#define TIF_FSCHECK 5 /* Check FS is USER_DS on return */
+#define TIF_MTE_ASYNC_FAULT 6 /* MTE Asynchronous Tag Check Fault */
#define TIF_NOHZ 7
#define TIF_SYSCALL_TRACE 8 /* syscall trace active */
#define TIF_SYSCALL_AUDIT 9 /* syscall auditing */
@@ -93,10 +94,11 @@ void arch_release_task_struct(struct task_struct *tsk);
#define _TIF_FSCHECK (1 << TIF_FSCHECK)
#define _TIF_32BIT (1 << TIF_32BIT)
#define _TIF_SVE (1 << TIF_SVE)
+#define _TIF_MTE_ASYNC_FAULT (1 << TIF_MTE_ASYNC_FAULT)
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
_TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \
- _TIF_UPROBE | _TIF_FSCHECK)
+ _TIF_UPROBE | _TIF_FSCHECK | _TIF_MTE_ASYNC_FAULT)
#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
_TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index fc6488660f64..d4a378bc0a60 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_CRASH_CORE) += crash_core.o
obj-$(CONFIG_ARM_SDE_INTERFACE) += sdei.o
obj-$(CONFIG_ARM64_SSBD) += ssbd.o
obj-$(CONFIG_ARM64_PTR_AUTH) += pointer_auth.o
+obj-$(CONFIG_ARM64_MTE) += mte.o
obj-y += vdso/ probes/
obj-$(CONFIG_COMPAT_VDSO) += vdso32/
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 9461d812ae27..9338b340e869 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -144,6 +144,22 @@ alternative_cb_end
#endif
.endm
+ /* Check for MTE asynchronous tag check faults */
+ .macro check_mte_async_tcf, flgs, tmp
+#ifdef CONFIG_ARM64_MTE
+alternative_if_not ARM64_MTE
+ b 1f
+alternative_else_nop_endif
+ mrs_s \tmp, SYS_TFSRE0_EL1
+ tbz \tmp, #SYS_TFSR_EL1_TF0_SHIFT, 1f
+ /* Asynchronous TCF occurred at EL0, set the TI flag */
+ orr \flgs, \flgs, #_TIF_MTE_ASYNC_FAULT
+ str \flgs, [tsk, #TSK_TI_FLAGS]
+ msr_s SYS_TFSRE0_EL1, xzr
+1:
+#endif
+ .endm
+
.macro kernel_entry, el, regsize = 64
.if \regsize == 32
mov w0, w0 // zero upper 32 bits of x0
@@ -175,6 +191,8 @@ alternative_cb_end
ldr x19, [tsk, #TSK_TI_FLAGS]
disable_step_tsk x19, x20
+ /* Check for asynchronous tag check faults in user space */
+ check_mte_async_tcf x19, x22
apply_ssbd 1, x22, x23
.else
@@ -242,6 +260,13 @@ alternative_if ARM64_HAS_IRQ_PRIO_MASKING
str x20, [sp, #S_PMR_SAVE]
alternative_else_nop_endif
+ /* Re-enable tag checking (TCO set on exception entry) */
+#ifdef CONFIG_ARM64_MTE
+alternative_if ARM64_MTE
+ SET_PSTATE_TCO(0)
+alternative_else_nop_endif
+#endif
+
/*
* Registers that may be useful after this macro is invoked:
*
@@ -738,6 +763,8 @@ work_pending:
*/
ret_to_user:
disable_daif
+ /* Check for asynchronous tag check faults in the uaccess routines */
+ check_mte_async_tcf x1, x2
gic_prio_kentry_setup tmp=x3
ldr x1, [tsk, #TSK_TI_FLAGS]
and x2, x1, #_TIF_WORK_MASK
diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
new file mode 100644
index 000000000000..0c2c900fa01c
--- /dev/null
+++ b/arch/arm64/kernel/mte.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020 ARM Ltd.
+ */
+
+#include <linux/thread_info.h>
+
+#include <asm/cpufeature.h>
+#include <asm/mte.h>
+#include <asm/sysreg.h>
+
+void flush_mte_state(void)
+{
+ if (!system_supports_mte())
+ return;
+
+ /* clear any pending asynchronous tag fault */
+ clear_thread_flag(TIF_MTE_ASYNC_FAULT);
+}
+
+void mte_thread_switch(struct task_struct *next)
+{
+ u64 tfsr;
+
+ if (!system_supports_mte())
+ return;
+
+ /*
+ * Check for asynchronous tag check faults from the uaccess routines
+ * before switching to the next thread.
+ */
+ tfsr = read_sysreg_s(SYS_TFSRE0_EL1);
+ if (tfsr & SYS_TFSR_EL1_TF0) {
+ set_thread_flag(TIF_MTE_ASYNC_FAULT);
+ write_sysreg_s(0, SYS_TFSRE0_EL1);
+ }
+}
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index bbb0f0c145f6..1b732150f51a 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -50,6 +50,7 @@
#include <asm/exec.h>
#include <asm/fpsimd.h>
#include <asm/mmu_context.h>
+#include <asm/mte.h>
#include <asm/processor.h>
#include <asm/pointer_auth.h>
#include <asm/stacktrace.h>
@@ -323,6 +324,7 @@ void flush_thread(void)
tls_thread_flush();
flush_ptrace_hw_breakpoint(current);
flush_tagged_addr_state();
+ flush_mte_state();
}
void release_thread(struct task_struct *dead_task)
@@ -507,6 +509,7 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
uao_thread_switch(next);
ptrauth_thread_switch(next);
ssbs_thread_switch(next);
+ mte_thread_switch(next);
/*
* Complete any pending TLB or cache maintenance on this CPU in case
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 339882db5a91..e377d77c065e 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -732,6 +732,9 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
regs->regs[29] = (unsigned long)&user->next_frame->fp;
regs->pc = (unsigned long)ka->sa.sa_handler;
+ /* TCO (Tag Check Override) always cleared for signal handlers */
+ regs->pstate &= ~PSR_TCO_BIT;
+
if (ka->sa.sa_flags & SA_RESTORER)
sigtramp = ka->sa.sa_restorer;
else
@@ -923,6 +926,11 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
if (thread_flags & _TIF_UPROBE)
uprobe_notify_resume(regs);
+ if (thread_flags & _TIF_MTE_ASYNC_FAULT) {
+ clear_thread_flag(TIF_MTE_ASYNC_FAULT);
+ force_signal_inject(SIGSEGV, SEGV_MTEAERR, 0);
+ }
+
if (thread_flags & _TIF_SIGPENDING)
do_signal(regs);
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index a12c0c88d345..db25f5d6a07c 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -102,6 +102,16 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
local_daif_restore(DAIF_PROCCTX);
user_exit();
+ if (system_supports_mte() && (flags & _TIF_MTE_ASYNC_FAULT)) {
+ /*
+ * Process the asynchronous tag check fault before the actual
+ * syscall. do_notify_resume() will send a signal to userspace
+ * before the syscall is restarted.
+ */
+ regs->regs[0] = -ERESTARTNOINTR;
+ return;
+ }
+
if (has_syscall_work(flags)) {
/* set default errno for user-issued syscall(-1) */
if (scno == NO_SYSCALL)
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 85566d32958f..cf2bf625ab92 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -660,6 +660,13 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
return 0;
}
+static int do_tag_check_fault(unsigned long addr, unsigned int esr,
+ struct pt_regs *regs)
+{
+ do_bad_area(addr, esr, regs);
+ return 0;
+}
+
static const struct fault_info fault_info[] = {
{ do_bad, SIGKILL, SI_KERNEL, "ttbr address size fault" },
{ do_bad, SIGKILL, SI_KERNEL, "level 1 address size fault" },
@@ -678,7 +685,7 @@ static const struct fault_info fault_info[] = {
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
{ do_sea, SIGBUS, BUS_OBJERR, "synchronous external abort" },
- { do_bad, SIGKILL, SI_KERNEL, "unknown 17" },
+ { do_tag_check_fault, SIGSEGV, SEGV_MTESERR, "synchronous tag check fault" },
{ do_bad, SIGKILL, SI_KERNEL, "unknown 18" },
{ do_bad, SIGKILL, SI_KERNEL, "unknown 19" },
{ do_sea, SIGKILL, SI_KERNEL, "level 0 (translation table walk)" },
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v2 10/19] arm64: mte: Handle synchronous and asynchronous tag check faults
2020-02-26 18:05 ` [PATCH v2 10/19] arm64: mte: Handle synchronous and asynchronous tag check faults Catalin Marinas
@ 2020-02-27 11:50 ` Catalin Marinas
0 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-27 11:50 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
On Wed, Feb 26, 2020 at 06:05:17PM +0000, Catalin Marinas wrote:
> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> index fc6488660f64..d4a378bc0a60 100644
> --- a/arch/arm64/kernel/Makefile
> +++ b/arch/arm64/kernel/Makefile
> @@ -63,6 +63,7 @@ obj-$(CONFIG_CRASH_CORE) += crash_core.o
> obj-$(CONFIG_ARM_SDE_INTERFACE) += sdei.o
> obj-$(CONFIG_ARM64_SSBD) += ssbd.o
> obj-$(CONFIG_ARM64_PTR_AUTH) += pointer_auth.o
> +obj-$(CONFIG_ARM64_MTE) += mte.o
>
> obj-y += vdso/ probes/
> obj-$(CONFIG_COMPAT_VDSO) += vdso32/
> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
> index 9461d812ae27..9338b340e869 100644
> --- a/arch/arm64/kernel/entry.S
> +++ b/arch/arm64/kernel/entry.S
[...]
> @@ -738,6 +763,8 @@ work_pending:
> */
> ret_to_user:
> disable_daif
> + /* Check for asynchronous tag check faults in the uaccess routines */
> + check_mte_async_tcf x1, x2
> gic_prio_kentry_setup tmp=x3
> ldr x1, [tsk, #TSK_TI_FLAGS]
> and x2, x1, #_TIF_WORK_MASK
I got this wrong, check_mte_async expects the flags as the first
argument (one may experience weird behaviour with overriding the TIF
flags; thanks to Kevin for debugging). The diff below should fix it:
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 9338b340e869..6e7f315911e8 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -764,9 +764,9 @@ work_pending:
ret_to_user:
disable_daif
/* Check for asynchronous tag check faults in the uaccess routines */
- check_mte_async_tcf x1, x2
gic_prio_kentry_setup tmp=x3
ldr x1, [tsk, #TSK_TI_FLAGS]
+ check_mte_async_tcf x1, x2
and x2, x1, #_TIF_WORK_MASK
cbnz x2, work_pending
finish_ret_to_user:
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 11/19] mm: Introduce arch_calc_vm_flag_bits()
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (9 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 10/19] arm64: mte: Handle synchronous and asynchronous tag check faults Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 12/19] arm64: mte: Add PROT_MTE support to mmap() and mprotect() Catalin Marinas
` (7 subsequent siblings)
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
From: Kevin Brodsky <Kevin.Brodsky@arm.com>
Similarly to arch_calc_vm_prot_bits(), introduce a dummy
arch_calc_vm_flag_bits() invoked from calc_vm_flag_bits(). This macro
can be overridden by architectures to insert specific VM_* flags derived
from the mmap() MAP_* flags.
Signed-off-by: Kevin Brodsky <Kevin.Brodsky@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
Notes:
v2:
- Updated the comment above arch_calc_vm_prot_bits().
- Changed author since this patch had already been posted (internally).
include/linux/mman.h | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/include/linux/mman.h b/include/linux/mman.h
index 4b08e9c9c538..15c1162b9d65 100644
--- a/include/linux/mman.h
+++ b/include/linux/mman.h
@@ -74,13 +74,17 @@ static inline void vm_unacct_memory(long pages)
}
/*
- * Allow architectures to handle additional protection bits
+ * Allow architectures to handle additional protection and flag bits
*/
#ifndef arch_calc_vm_prot_bits
#define arch_calc_vm_prot_bits(prot, pkey) 0
#endif
+#ifndef arch_calc_vm_flag_bits
+#define arch_calc_vm_flag_bits(flags) 0
+#endif
+
#ifndef arch_vm_get_page_prot
#define arch_vm_get_page_prot(vm_flags) __pgprot(0)
#endif
@@ -131,7 +135,8 @@ calc_vm_flag_bits(unsigned long flags)
return _calc_vm_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN ) |
_calc_vm_trans(flags, MAP_DENYWRITE, VM_DENYWRITE ) |
_calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED ) |
- _calc_vm_trans(flags, MAP_SYNC, VM_SYNC );
+ _calc_vm_trans(flags, MAP_SYNC, VM_SYNC ) |
+ arch_calc_vm_flag_bits(flags);
}
unsigned long vm_commit_limit(void);
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 12/19] arm64: mte: Add PROT_MTE support to mmap() and mprotect()
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (10 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 11/19] mm: Introduce arch_calc_vm_flag_bits() Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 13/19] mm: Introduce arch_validate_flags() Catalin Marinas
` (6 subsequent siblings)
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
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>
---
Notes:
v2:
- Add VM_MTE_ALLOWED to show_smap_vma_flags().
arch/arm64/include/asm/memory.h | 18 +++++----
arch/arm64/include/asm/mman.h | 64 ++++++++++++++++++++++++++++++
arch/arm64/include/asm/page.h | 4 +-
arch/arm64/include/asm/pgtable.h | 7 +++-
arch/arm64/include/uapi/asm/mman.h | 14 +++++++
fs/proc/task_mmu.c | 4 ++
include/linux/mm.h | 8 ++++
7 files changed, 110 insertions(+), 9 deletions(-)
create mode 100644 arch/arm64/include/asm/mman.h
create mode 100644 arch/arm64/include/uapi/asm/mman.h
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 55994ab362ae..f0e535895a78 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -138,14 +138,18 @@
/*
* Memory types available.
+ *
+ * IMPORTANT: MT_NORMAL must be index 0 since vm_get_page_prot() may 'or' in
+ * the MT_NORMAL_TAGGED memory type for PROT_MTE mappings. Note
+ * that protection_map[] only contains MT_NORMAL attributes.
*/
-#define MT_DEVICE_nGnRnE 0
-#define MT_DEVICE_nGnRE 1
-#define MT_DEVICE_GRE 2
-#define MT_NORMAL_NC 3
-#define MT_NORMAL 4
-#define MT_NORMAL_WT 5
-#define MT_NORMAL_TAGGED 6
+#define MT_NORMAL 0
+#define MT_NORMAL_TAGGED 1
+#define MT_NORMAL_NC 2
+#define MT_NORMAL_WT 3
+#define MT_DEVICE_nGnRnE 4
+#define MT_DEVICE_nGnRE 5
+#define MT_DEVICE_GRE 6
/*
* Memory types for Stage-2 translation
diff --git a/arch/arm64/include/asm/mman.h b/arch/arm64/include/asm/mman.h
new file mode 100644
index 000000000000..c77a23869223
--- /dev/null
+++ b/arch/arm64/include/asm/mman.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_MMAN_H__
+#define __ASM_MMAN_H__
+
+#include <uapi/asm/mman.h>
+
+/*
+ * There are two conditions required for returning a Normal Tagged memory type
+ * in arch_vm_get_page_prot(): (1) the user requested it via PROT_MTE passed
+ * to mmap() or mprotect() and (2) the corresponding vma supports MTE. We
+ * register (1) as VM_MTE in the vma->vm_flags and (2) as VM_MTE_ALLOWED. Note
+ * that the latter can only be set during the mmap() call since mprotect()
+ * does not accept MAP_* flags.
+ */
+static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot,
+ unsigned long pkey)
+{
+ if (!system_supports_mte())
+ return 0;
+
+ if (prot & PROT_MTE)
+ return VM_MTE;
+
+ return 0;
+}
+#define arch_calc_vm_prot_bits arch_calc_vm_prot_bits
+
+static inline unsigned long arch_calc_vm_flag_bits(unsigned long flags)
+{
+ if (!system_supports_mte())
+ return 0;
+
+ /*
+ * Only allow MTE on anonymous mappings as these are guaranteed to be
+ * backed by tags-capable memory. The vm_flags may be overridden by a
+ * filesystem supporting MTE (RAM-based).
+ */
+ if (flags & MAP_ANONYMOUS)
+ return VM_MTE_ALLOWED;
+
+ return 0;
+}
+#define arch_calc_vm_flag_bits arch_calc_vm_flag_bits
+
+static inline pgprot_t arch_vm_get_page_prot(unsigned long vm_flags)
+{
+ return (vm_flags & VM_MTE) && (vm_flags & VM_MTE_ALLOWED) ?
+ __pgprot(PTE_ATTRINDX(MT_NORMAL_TAGGED)) :
+ __pgprot(0);
+}
+#define arch_vm_get_page_prot arch_vm_get_page_prot
+
+static inline bool arch_validate_prot(unsigned long prot, unsigned long addr)
+{
+ unsigned long supported = PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM;
+
+ if (system_supports_mte())
+ supported |= PROT_MTE;
+
+ return (prot & ~supported) == 0;
+}
+#define arch_validate_prot arch_validate_prot
+
+#endif /* !__ASM_MMAN_H__ */
diff --git a/arch/arm64/include/asm/page.h b/arch/arm64/include/asm/page.h
index d39ddb258a04..10d71f927b70 100644
--- a/arch/arm64/include/asm/page.h
+++ b/arch/arm64/include/asm/page.h
@@ -32,9 +32,11 @@ extern int pfn_valid(unsigned long);
#endif /* !__ASSEMBLY__ */
+/* Used for stack and brk memory ranges */
#define VM_DATA_DEFAULT_FLAGS \
(((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
- VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+ VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC | \
+ VM_MTE_ALLOWED)
#include <asm-generic/getorder.h>
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 538c85e62f86..39a372bf8afc 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -659,8 +659,13 @@ static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
+ /*
+ * Normal and Normal-Tagged are two different memory types and indices
+ * in MAIR_EL1. The mask below has to include PTE_ATTRINDX_MASK.
+ */
const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
- PTE_PROT_NONE | PTE_VALID | PTE_WRITE;
+ PTE_PROT_NONE | PTE_VALID | PTE_WRITE |
+ PTE_ATTRINDX_MASK;
/* preserve the hardware dirty information */
if (pte_hw_dirty(pte))
pte = pte_mkdirty(pte);
diff --git a/arch/arm64/include/uapi/asm/mman.h b/arch/arm64/include/uapi/asm/mman.h
new file mode 100644
index 000000000000..d7677ee84878
--- /dev/null
+++ b/arch/arm64/include/uapi/asm/mman.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI__ASM_MMAN_H
+#define _UAPI__ASM_MMAN_H
+
+#include <asm-generic/mman.h>
+
+/*
+ * The generic mman.h file reserves 0x10 and 0x20 for arch-specific PROT_*
+ * flags.
+ */
+/* 0x10 reserved for PROT_BTI */
+#define PROT_MTE 0x20 /* Normal Tagged mapping */
+
+#endif /* !_UAPI__ASM_MMAN_H */
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 3ba9ae83bff5..09d0ede63899 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -677,6 +677,10 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
[ilog2(VM_MERGEABLE)] = "mg",
[ilog2(VM_UFFD_MISSING)]= "um",
[ilog2(VM_UFFD_WP)] = "uw",
+#ifdef CONFIG_ARM64_MTE
+ [ilog2(VM_MTE)] = "mt",
+ [ilog2(VM_MTE_ALLOWED)] = "",
+#endif
#ifdef CONFIG_ARCH_HAS_PKEYS
/* These come out via ProtectionKey: */
[ilog2(VM_PKEY_BIT0)] = "",
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 52269e56c514..e7f1f404f0e1 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -335,6 +335,14 @@ extern unsigned int kobjsize(const void *objp);
# define VM_MPX VM_NONE
#endif
+#if defined(CONFIG_ARM64_MTE)
+# define VM_MTE VM_HIGH_ARCH_0 /* Use Tagged memory for access control */
+# define VM_MTE_ALLOWED VM_HIGH_ARCH_1 /* Tagged memory permitted */
+#else
+# define VM_MTE VM_NONE
+# define VM_MTE_ALLOWED VM_NONE
+#endif
+
#ifndef VM_GROWSUP
# define VM_GROWSUP VM_NONE
#endif
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 13/19] mm: Introduce arch_validate_flags()
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (11 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 12/19] arm64: mte: Add PROT_MTE support to mmap() and mprotect() Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 14/19] arm64: mte: Validate the PROT_MTE request via arch_validate_flags() Catalin Marinas
` (5 subsequent siblings)
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
Similarly to arch_validate_prot() called from do_mprotect_pkey(), an
architecture may need to sanity-check the new vm_flags.
Define a dummy function always returning true. In addition to
do_mprotect_pkey(), also invoke it from mmap_region() prior to updating
vma->vm_page_prot to allow the architecture code to veto potentially
inconsistent vm_flags.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
Notes:
v2:
- Some comments updated.
include/linux/mman.h | 13 +++++++++++++
mm/mmap.c | 9 +++++++++
mm/mprotect.c | 6 ++++++
3 files changed, 28 insertions(+)
diff --git a/include/linux/mman.h b/include/linux/mman.h
index 15c1162b9d65..09dd414b81b6 100644
--- a/include/linux/mman.h
+++ b/include/linux/mman.h
@@ -103,6 +103,19 @@ static inline bool arch_validate_prot(unsigned long prot, unsigned long addr)
#define arch_validate_prot arch_validate_prot
#endif
+#ifndef arch_validate_flags
+/*
+ * This is called from mmap() and mprotect() with the updated vma->vm_flags.
+ *
+ * Returns true if the VM_* flags are valid.
+ */
+static inline bool arch_validate_flags(unsigned long flags)
+{
+ return true;
+}
+#define arch_validate_flags arch_validate_flags
+#endif
+
/*
* Optimisation macro. It is equivalent to:
* (x & bit1) ? bit2 : 0
diff --git a/mm/mmap.c b/mm/mmap.c
index 6756b8bb0033..e52e433849c3 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1794,6 +1794,15 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
vma_set_anonymous(vma);
}
+ /* Allow architectures to sanity-check the vm_flags */
+ if (!arch_validate_flags(vma->vm_flags)) {
+ error = -EINVAL;
+ if (file)
+ goto unmap_and_free_vma;
+ else
+ goto free_vma;
+ }
+
vma_link(mm, vma, prev, rb_link, rb_parent);
/* Once vma denies write, undo our temporary denial count */
if (file) {
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 7a8e84f86831..1c760058ace3 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -543,6 +543,12 @@ static int do_mprotect_pkey(unsigned long start, size_t len,
goto out;
}
+ /* Allow architectures to sanity-check the new flags */
+ if (!arch_validate_flags(newflags)) {
+ error = -EINVAL;
+ goto out;
+ }
+
error = security_file_mprotect(vma, reqprot, prot);
if (error)
goto out;
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 14/19] arm64: mte: Validate the PROT_MTE request via arch_validate_flags()
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (12 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 13/19] mm: Introduce arch_validate_flags() Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 15/19] mm: Allow arm64 mmap(PROT_MTE) on RAM-based files Catalin Marinas
` (4 subsequent siblings)
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
Make use of the newly introduced arch_validate_flags() hook to
sanity-check the PROT_MTE request passed to mmap() and mprotect(). If
the mapping does not support MTE, these syscalls will return -EINVAL.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm64/include/asm/mman.h | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/mman.h b/arch/arm64/include/asm/mman.h
index c77a23869223..5c356d1ca266 100644
--- a/arch/arm64/include/asm/mman.h
+++ b/arch/arm64/include/asm/mman.h
@@ -44,7 +44,11 @@ static inline unsigned long arch_calc_vm_flag_bits(unsigned long flags)
static inline pgprot_t arch_vm_get_page_prot(unsigned long vm_flags)
{
- return (vm_flags & VM_MTE) && (vm_flags & VM_MTE_ALLOWED) ?
+ /*
+ * Checking for VM_MTE only is sufficient since arch_validate_flags()
+ * does not permit (VM_MTE & !VM_MTE_ALLOWED).
+ */
+ return (vm_flags & VM_MTE) ?
__pgprot(PTE_ATTRINDX(MT_NORMAL_TAGGED)) :
__pgprot(0);
}
@@ -61,4 +65,14 @@ static inline bool arch_validate_prot(unsigned long prot, unsigned long addr)
}
#define arch_validate_prot arch_validate_prot
+static inline bool arch_validate_flags(unsigned long flags)
+{
+ if (!system_supports_mte())
+ return true;
+
+ /* only allow VM_MTE if VM_MTE_ALLOWED has been set previously */
+ return !(flags & VM_MTE) || (flags & VM_MTE_ALLOWED);
+}
+#define arch_validate_flags arch_validate_flags
+
#endif /* !__ASM_MMAN_H__ */
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 15/19] mm: Allow arm64 mmap(PROT_MTE) on RAM-based files
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (13 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 14/19] arm64: mte: Validate the PROT_MTE request via arch_validate_flags() Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 16/19] arm64: mte: Allow user control of the tag check mode via prctl() Catalin Marinas
` (3 subsequent siblings)
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
Since arm64 memory (allocation) tags can only be stored in RAM, mapping
files with PROT_MTE is not allowed by default. RAM-based files like
those in a tmpfs mount or memfd_create() can support memory tagging, so
update the vm_flags accordingly in shmem_mmap().
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
mm/shmem.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/mm/shmem.c b/mm/shmem.c
index c8f7540ef048..afd050ac7f8d 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2226,6 +2226,9 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_flags &= ~(VM_MAYWRITE);
}
+ /* arm64 - allow memory tagging on RAM-based files */
+ vma->vm_flags |= VM_MTE_ALLOWED;
+
file_accessed(file);
vma->vm_ops = &shmem_vm_ops;
if (IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE) &&
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 16/19] arm64: mte: Allow user control of the tag check mode via prctl()
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (14 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 15/19] mm: Allow arm64 mmap(PROT_MTE) on RAM-based files Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-03-09 13:53 ` Kevin Brodsky
2020-02-26 18:05 ` [PATCH v2 17/19] arm64: mte: Allow user control of the generated random tags " Catalin Marinas
` (2 subsequent siblings)
18 siblings, 1 reply; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
By default, even if PROT_MTE is set on a memory range, there is no tag
check fault reporting (SIGSEGV). Introduce a set of option to the
exiting prctl(PR_SET_TAGGED_ADDR_CTRL) to allow user control of the tag
check fault mode:
PR_MTE_TCF_NONE - no reporting (default)
PR_MTE_TCF_SYNC - synchronous tag check fault reporting
PR_MTE_TCF_ASYNC - asynchronous tag check fault reporting
These options translate into the corresponding SCTLR_EL1.TCF0 bitfield,
context-switched by the kernel. Note that uaccess done by the kernel is
not checked and cannot be configured by the user.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
Notes:
v2:
- Handle SCTLR_EL1_TCF0_NONE explicitly for consistency with PR_MTE_TCF_NONE.
- Fix SCTLR_EL1 register setting in flush_mte_state() (thanks to Peter
Collingbourne).
- Added ISB to update_sctlr_el1_tcf0() since, with the latest
architecture update/fix, the TCF0 field is used by the uaccess
routines.
arch/arm64/include/asm/mte.h | 10 +++++
arch/arm64/include/asm/processor.h | 3 ++
arch/arm64/kernel/mte.c | 71 ++++++++++++++++++++++++++++++
arch/arm64/kernel/process.c | 19 ++++++--
include/uapi/linux/prctl.h | 6 +++
5 files changed, 106 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/include/asm/mte.h b/arch/arm64/include/asm/mte.h
index 0d7f7ca07ee6..3dc0a7977124 100644
--- a/arch/arm64/include/asm/mte.h
+++ b/arch/arm64/include/asm/mte.h
@@ -12,6 +12,8 @@ int mte_memcmp_pages(const void *page1_addr, const void *page2_addr);
#ifdef CONFIG_ARM64_MTE
void flush_mte_state(void);
void mte_thread_switch(struct task_struct *next);
+long set_mte_ctrl(unsigned long arg);
+long get_mte_ctrl(void);
#else
static inline void flush_mte_state(void)
{
@@ -19,6 +21,14 @@ static inline void flush_mte_state(void)
static inline void mte_thread_switch(struct task_struct *next)
{
}
+static inline long set_mte_ctrl(unsigned long arg)
+{
+ return 0;
+}
+static inline long get_mte_ctrl(void)
+{
+ return 0;
+}
#endif
#endif /* __ASSEMBLY__ */
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 5ba63204d078..91aa270afc7d 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -148,6 +148,9 @@ struct thread_struct {
#ifdef CONFIG_ARM64_PTR_AUTH
struct ptrauth_keys keys_user;
#endif
+#ifdef CONFIG_ARM64_MTE
+ u64 sctlr_tcf0;
+#endif
};
static inline void arch_thread_struct_whitelist(unsigned long *offset,
diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
index 0c2c900fa01c..4b926d779940 100644
--- a/arch/arm64/kernel/mte.c
+++ b/arch/arm64/kernel/mte.c
@@ -3,12 +3,34 @@
* Copyright (C) 2020 ARM Ltd.
*/
+#include <linux/prctl.h>
+#include <linux/sched.h>
#include <linux/thread_info.h>
#include <asm/cpufeature.h>
#include <asm/mte.h>
#include <asm/sysreg.h>
+static void update_sctlr_el1_tcf0(u64 tcf0)
+{
+ /* ISB required for the kernel uaccess routines */
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_TCF0_MASK, tcf0);
+ isb();
+}
+
+static void set_sctlr_el1_tcf0(u64 tcf0)
+{
+ /*
+ * mte_thread_switch() checks current->thread.sctlr_tcf0 as an
+ * optimisation. Disable preemption so that it does not see
+ * the variable update before the SCTLR_EL1.TCF0 one.
+ */
+ preempt_disable();
+ current->thread.sctlr_tcf0 = tcf0;
+ update_sctlr_el1_tcf0(tcf0);
+ preempt_enable();
+}
+
void flush_mte_state(void)
{
if (!system_supports_mte())
@@ -16,6 +38,8 @@ void flush_mte_state(void)
/* clear any pending asynchronous tag fault */
clear_thread_flag(TIF_MTE_ASYNC_FAULT);
+ /* disable tag checking */
+ set_sctlr_el1_tcf0(0);
}
void mte_thread_switch(struct task_struct *next)
@@ -34,4 +58,51 @@ void mte_thread_switch(struct task_struct *next)
set_thread_flag(TIF_MTE_ASYNC_FAULT);
write_sysreg_s(0, SYS_TFSRE0_EL1);
}
+
+ /* avoid expensive SCTLR_EL1 accesses if no change */
+ if (current->thread.sctlr_tcf0 != next->thread.sctlr_tcf0)
+ update_sctlr_el1_tcf0(next->thread.sctlr_tcf0);
+}
+
+long set_mte_ctrl(unsigned long arg)
+{
+ u64 tcf0;
+
+ if (!system_supports_mte())
+ return 0;
+
+ switch (arg & PR_MTE_TCF_MASK) {
+ case PR_MTE_TCF_NONE:
+ tcf0 = SCTLR_EL1_TCF0_NONE;
+ break;
+ case PR_MTE_TCF_SYNC:
+ tcf0 = SCTLR_EL1_TCF0_SYNC;
+ break;
+ case PR_MTE_TCF_ASYNC:
+ tcf0 = SCTLR_EL1_TCF0_ASYNC;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ set_sctlr_el1_tcf0(tcf0);
+
+ return 0;
+}
+
+long get_mte_ctrl(void)
+{
+ if (!system_supports_mte())
+ return 0;
+
+ switch (current->thread.sctlr_tcf0) {
+ case SCTLR_EL1_TCF0_NONE:
+ return PR_MTE_TCF_NONE;
+ case SCTLR_EL1_TCF0_SYNC:
+ return PR_MTE_TCF_SYNC;
+ case SCTLR_EL1_TCF0_ASYNC:
+ return PR_MTE_TCF_ASYNC;
+ }
+
+ return 0;
}
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 1b732150f51a..b3c8cd64b88a 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -578,9 +578,15 @@ static unsigned int tagged_addr_disabled;
long set_tagged_addr_ctrl(unsigned long arg)
{
+ unsigned long valid_mask = PR_TAGGED_ADDR_ENABLE;
+
if (is_compat_task())
return -EINVAL;
- if (arg & ~PR_TAGGED_ADDR_ENABLE)
+
+ if (system_supports_mte())
+ valid_mask |= PR_MTE_TCF_MASK;
+
+ if (arg & ~valid_mask)
return -EINVAL;
/*
@@ -590,6 +596,9 @@ long set_tagged_addr_ctrl(unsigned long arg)
if (arg & PR_TAGGED_ADDR_ENABLE && tagged_addr_disabled)
return -EINVAL;
+ if (set_mte_ctrl(arg) != 0)
+ return -EINVAL;
+
update_thread_flag(TIF_TAGGED_ADDR, arg & PR_TAGGED_ADDR_ENABLE);
return 0;
@@ -597,13 +606,17 @@ long set_tagged_addr_ctrl(unsigned long arg)
long get_tagged_addr_ctrl(void)
{
+ long ret = 0;
+
if (is_compat_task())
return -EINVAL;
if (test_thread_flag(TIF_TAGGED_ADDR))
- return PR_TAGGED_ADDR_ENABLE;
+ ret = PR_TAGGED_ADDR_ENABLE;
- return 0;
+ ret |= get_mte_ctrl();
+
+ return ret;
}
/*
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 07b4f8131e36..2390ab324afa 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -233,6 +233,12 @@ struct prctl_mm_map {
#define PR_SET_TAGGED_ADDR_CTRL 55
#define PR_GET_TAGGED_ADDR_CTRL 56
# define PR_TAGGED_ADDR_ENABLE (1UL << 0)
+/* MTE tag check fault modes */
+# define PR_MTE_TCF_SHIFT 1
+# define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT)
+# define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
+# define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT)
+# define PR_MTE_TCF_MASK (3UL << PR_MTE_TCF_SHIFT)
/* Control reclaim behavior when allocating memory */
#define PR_SET_IO_FLUSHER 57
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v2 16/19] arm64: mte: Allow user control of the tag check mode via prctl()
2020-02-26 18:05 ` [PATCH v2 16/19] arm64: mte: Allow user control of the tag check mode via prctl() Catalin Marinas
@ 2020-03-09 13:53 ` Kevin Brodsky
0 siblings, 0 replies; 32+ messages in thread
From: Kevin Brodsky @ 2020-03-09 13:53 UTC (permalink / raw)
To: Catalin Marinas, linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Peter Collingbourne,
linux-mm, Andrey Konovalov, Vincenzo Frascino, Will Deacon
On 26/02/2020 18:05, Catalin Marinas wrote:
> By default, even if PROT_MTE is set on a memory range, there is no tag
> check fault reporting (SIGSEGV). Introduce a set of option to the
> exiting prctl(PR_SET_TAGGED_ADDR_CTRL) to allow user control of the tag
> check fault mode:
>
> PR_MTE_TCF_NONE - no reporting (default)
> PR_MTE_TCF_SYNC - synchronous tag check fault reporting
> PR_MTE_TCF_ASYNC - asynchronous tag check fault reporting
>
> These options translate into the corresponding SCTLR_EL1.TCF0 bitfield,
> context-switched by the kernel. Note that uaccess done by the kernel is
> not checked and cannot be configured by the user.
>
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> ---
>
> Notes:
> v2:
> - Handle SCTLR_EL1_TCF0_NONE explicitly for consistency with PR_MTE_TCF_NONE.
> - Fix SCTLR_EL1 register setting in flush_mte_state() (thanks to Peter
> Collingbourne).
> - Added ISB to update_sctlr_el1_tcf0() since, with the latest
> architecture update/fix, the TCF0 field is used by the uaccess
> routines.
>
> arch/arm64/include/asm/mte.h | 10 +++++
> arch/arm64/include/asm/processor.h | 3 ++
> arch/arm64/kernel/mte.c | 71 ++++++++++++++++++++++++++++++
> arch/arm64/kernel/process.c | 19 ++++++--
> include/uapi/linux/prctl.h | 6 +++
> 5 files changed, 106 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm64/include/asm/mte.h b/arch/arm64/include/asm/mte.h
> index 0d7f7ca07ee6..3dc0a7977124 100644
> --- a/arch/arm64/include/asm/mte.h
> +++ b/arch/arm64/include/asm/mte.h
> @@ -12,6 +12,8 @@ int mte_memcmp_pages(const void *page1_addr, const void *page2_addr);
> #ifdef CONFIG_ARM64_MTE
> void flush_mte_state(void);
> void mte_thread_switch(struct task_struct *next);
> +long set_mte_ctrl(unsigned long arg);
> +long get_mte_ctrl(void);
> #else
> static inline void flush_mte_state(void)
> {
> @@ -19,6 +21,14 @@ static inline void flush_mte_state(void)
> static inline void mte_thread_switch(struct task_struct *next)
> {
> }
> +static inline long set_mte_ctrl(unsigned long arg)
> +{
> + return 0;
> +}
> +static inline long get_mte_ctrl(void)
> +{
> + return 0;
> +}
> #endif
>
> #endif /* __ASSEMBLY__ */
> diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
> index 5ba63204d078..91aa270afc7d 100644
> --- a/arch/arm64/include/asm/processor.h
> +++ b/arch/arm64/include/asm/processor.h
> @@ -148,6 +148,9 @@ struct thread_struct {
> #ifdef CONFIG_ARM64_PTR_AUTH
> struct ptrauth_keys keys_user;
> #endif
> +#ifdef CONFIG_ARM64_MTE
> + u64 sctlr_tcf0;
> +#endif
> };
>
> static inline void arch_thread_struct_whitelist(unsigned long *offset,
> diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
> index 0c2c900fa01c..4b926d779940 100644
> --- a/arch/arm64/kernel/mte.c
> +++ b/arch/arm64/kernel/mte.c
> @@ -3,12 +3,34 @@
> * Copyright (C) 2020 ARM Ltd.
> */
>
> +#include <linux/prctl.h>
> +#include <linux/sched.h>
> #include <linux/thread_info.h>
>
> #include <asm/cpufeature.h>
> #include <asm/mte.h>
> #include <asm/sysreg.h>
>
> +static void update_sctlr_el1_tcf0(u64 tcf0)
> +{
> + /* ISB required for the kernel uaccess routines */
> + sysreg_clear_set(sctlr_el1, SCTLR_EL1_TCF0_MASK, tcf0);
> + isb();
> +}
> +
> +static void set_sctlr_el1_tcf0(u64 tcf0)
> +{
> + /*
> + * mte_thread_switch() checks current->thread.sctlr_tcf0 as an
> + * optimisation. Disable preemption so that it does not see
> + * the variable update before the SCTLR_EL1.TCF0 one.
> + */
> + preempt_disable();
> + current->thread.sctlr_tcf0 = tcf0;
> + update_sctlr_el1_tcf0(tcf0);
> + preempt_enable();
> +}
> +
> void flush_mte_state(void)
> {
> if (!system_supports_mte())
> @@ -16,6 +38,8 @@ void flush_mte_state(void)
>
> /* clear any pending asynchronous tag fault */
> clear_thread_flag(TIF_MTE_ASYNC_FAULT);
> + /* disable tag checking */
> + set_sctlr_el1_tcf0(0);
For consistency: set_sctlr_el1_tcf0(SCTLR_EL1_TCF0_NONE);
Kevin
> }
>
> void mte_thread_switch(struct task_struct *next)
> @@ -34,4 +58,51 @@ void mte_thread_switch(struct task_struct *next)
> set_thread_flag(TIF_MTE_ASYNC_FAULT);
> write_sysreg_s(0, SYS_TFSRE0_EL1);
> }
> +
> + /* avoid expensive SCTLR_EL1 accesses if no change */
> + if (current->thread.sctlr_tcf0 != next->thread.sctlr_tcf0)
> + update_sctlr_el1_tcf0(next->thread.sctlr_tcf0);
> +}
> +
> +long set_mte_ctrl(unsigned long arg)
> +{
> + u64 tcf0;
> +
> + if (!system_supports_mte())
> + return 0;
> +
> + switch (arg & PR_MTE_TCF_MASK) {
> + case PR_MTE_TCF_NONE:
> + tcf0 = SCTLR_EL1_TCF0_NONE;
> + break;
> + case PR_MTE_TCF_SYNC:
> + tcf0 = SCTLR_EL1_TCF0_SYNC;
> + break;
> + case PR_MTE_TCF_ASYNC:
> + tcf0 = SCTLR_EL1_TCF0_ASYNC;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + set_sctlr_el1_tcf0(tcf0);
> +
> + return 0;
> +}
> +
> +long get_mte_ctrl(void)
> +{
> + if (!system_supports_mte())
> + return 0;
> +
> + switch (current->thread.sctlr_tcf0) {
> + case SCTLR_EL1_TCF0_NONE:
> + return PR_MTE_TCF_NONE;
> + case SCTLR_EL1_TCF0_SYNC:
> + return PR_MTE_TCF_SYNC;
> + case SCTLR_EL1_TCF0_ASYNC:
> + return PR_MTE_TCF_ASYNC;
> + }
> +
> + return 0;
> }
> diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
> index 1b732150f51a..b3c8cd64b88a 100644
> --- a/arch/arm64/kernel/process.c
> +++ b/arch/arm64/kernel/process.c
> @@ -578,9 +578,15 @@ static unsigned int tagged_addr_disabled;
>
> long set_tagged_addr_ctrl(unsigned long arg)
> {
> + unsigned long valid_mask = PR_TAGGED_ADDR_ENABLE;
> +
> if (is_compat_task())
> return -EINVAL;
> - if (arg & ~PR_TAGGED_ADDR_ENABLE)
> +
> + if (system_supports_mte())
> + valid_mask |= PR_MTE_TCF_MASK;
> +
> + if (arg & ~valid_mask)
> return -EINVAL;
>
> /*
> @@ -590,6 +596,9 @@ long set_tagged_addr_ctrl(unsigned long arg)
> if (arg & PR_TAGGED_ADDR_ENABLE && tagged_addr_disabled)
> return -EINVAL;
>
> + if (set_mte_ctrl(arg) != 0)
> + return -EINVAL;
> +
> update_thread_flag(TIF_TAGGED_ADDR, arg & PR_TAGGED_ADDR_ENABLE);
>
> return 0;
> @@ -597,13 +606,17 @@ long set_tagged_addr_ctrl(unsigned long arg)
>
> long get_tagged_addr_ctrl(void)
> {
> + long ret = 0;
> +
> if (is_compat_task())
> return -EINVAL;
>
> if (test_thread_flag(TIF_TAGGED_ADDR))
> - return PR_TAGGED_ADDR_ENABLE;
> + ret = PR_TAGGED_ADDR_ENABLE;
>
> - return 0;
> + ret |= get_mte_ctrl();
> +
> + return ret;
> }
>
> /*
> diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
> index 07b4f8131e36..2390ab324afa 100644
> --- a/include/uapi/linux/prctl.h
> +++ b/include/uapi/linux/prctl.h
> @@ -233,6 +233,12 @@ struct prctl_mm_map {
> #define PR_SET_TAGGED_ADDR_CTRL 55
> #define PR_GET_TAGGED_ADDR_CTRL 56
> # define PR_TAGGED_ADDR_ENABLE (1UL << 0)
> +/* MTE tag check fault modes */
> +# define PR_MTE_TCF_SHIFT 1
> +# define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT)
> +# define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
> +# define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT)
> +# define PR_MTE_TCF_MASK (3UL << PR_MTE_TCF_SHIFT)
>
> /* Control reclaim behavior when allocating memory */
> #define PR_SET_IO_FLUSHER 57
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 17/19] arm64: mte: Allow user control of the generated random tags via prctl()
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (15 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 16/19] arm64: mte: Allow user control of the tag check mode via prctl() Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 18/19] arm64: mte: Kconfig entry Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 19/19] arm64: mte: Add Memory Tagging Extension documentation Catalin Marinas
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
The IRG, ADDG and SUBG instructions insert a random tag in the resulting
address. Certain tags can be excluded via the GCR_EL1.Exclude bitmap
when, for example, the user wants a certain colour for freed buffers.
Since the GCR_EL1 register is not accessible at EL0, extend the
prctl(PR_SET_TAGGED_ADDR_CTRL) interface to include a 16-bit field in
the first argument for controlling which tags can be generated by the
above instruction (an include rather than exclude mask). Note that by
default all non-zero tags are excluded. This setting is per-thread.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
Notes:
v2:
- Switch from an exclude mask to an include one for the prctl()
interface.
- Reset the allowed tags mask during flush_thread().
arch/arm64/include/asm/processor.h | 1 +
arch/arm64/include/asm/sysreg.h | 7 ++++++
arch/arm64/kernel/mte.c | 35 +++++++++++++++++++++++++++---
arch/arm64/kernel/process.c | 2 +-
include/uapi/linux/prctl.h | 3 +++
5 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 91aa270afc7d..bd215d74275d 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -150,6 +150,7 @@ struct thread_struct {
#endif
#ifdef CONFIG_ARM64_MTE
u64 sctlr_tcf0;
+ u64 gcr_incl;
#endif
};
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 13f0841b6ed3..dd8d747997be 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -931,6 +931,13 @@
write_sysreg(__scs_new, sysreg); \
} while (0)
+#define sysreg_clear_set_s(sysreg, clear, set) do { \
+ u64 __scs_val = read_sysreg_s(sysreg); \
+ u64 __scs_new = (__scs_val & ~(u64)(clear)) | (set); \
+ if (__scs_new != __scs_val) \
+ write_sysreg_s(__scs_new, sysreg); \
+} while (0)
+
#endif
#endif /* __ASM_SYSREG_H */
diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
index 4b926d779940..0cd1482b18a0 100644
--- a/arch/arm64/kernel/mte.c
+++ b/arch/arm64/kernel/mte.c
@@ -31,6 +31,25 @@ static void set_sctlr_el1_tcf0(u64 tcf0)
preempt_enable();
}
+static void update_gcr_el1_excl(u64 incl)
+{
+ u64 excl = ~incl & SYS_GCR_EL1_EXCL_MASK;
+
+ /*
+ * Note that 'incl' is an include mask (controlled by the user via
+ * prctl()) while GCR_EL1 accepts an exclude mask.
+ * No need for ISB since this only affects EL0 currently, implicit
+ * with ERET.
+ */
+ sysreg_clear_set_s(SYS_GCR_EL1, SYS_GCR_EL1_EXCL_MASK, excl);
+}
+
+static void set_gcr_el1_excl(u64 incl)
+{
+ current->thread.gcr_incl = incl;
+ update_gcr_el1_excl(incl);
+}
+
void flush_mte_state(void)
{
if (!system_supports_mte())
@@ -40,6 +59,8 @@ void flush_mte_state(void)
clear_thread_flag(TIF_MTE_ASYNC_FAULT);
/* disable tag checking */
set_sctlr_el1_tcf0(0);
+ /* reset tag generation mask */
+ set_gcr_el1_excl(0);
}
void mte_thread_switch(struct task_struct *next)
@@ -62,6 +83,7 @@ void mte_thread_switch(struct task_struct *next)
/* avoid expensive SCTLR_EL1 accesses if no change */
if (current->thread.sctlr_tcf0 != next->thread.sctlr_tcf0)
update_sctlr_el1_tcf0(next->thread.sctlr_tcf0);
+ update_gcr_el1_excl(next->thread.gcr_incl);
}
long set_mte_ctrl(unsigned long arg)
@@ -86,23 +108,30 @@ long set_mte_ctrl(unsigned long arg)
}
set_sctlr_el1_tcf0(tcf0);
+ set_gcr_el1_excl((arg & PR_MTE_TAG_MASK) >> PR_MTE_TAG_SHIFT);
return 0;
}
long get_mte_ctrl(void)
{
+ unsigned long ret;
+
if (!system_supports_mte())
return 0;
+ ret = current->thread.gcr_incl << PR_MTE_TAG_SHIFT;
+
switch (current->thread.sctlr_tcf0) {
case SCTLR_EL1_TCF0_NONE:
return PR_MTE_TCF_NONE;
case SCTLR_EL1_TCF0_SYNC:
- return PR_MTE_TCF_SYNC;
+ ret |= PR_MTE_TCF_SYNC;
+ break;
case SCTLR_EL1_TCF0_ASYNC:
- return PR_MTE_TCF_ASYNC;
+ ret |= PR_MTE_TCF_ASYNC;
+ break;
}
- return 0;
+ return ret;
}
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index b3c8cd64b88a..4ac0e90617fc 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -584,7 +584,7 @@ long set_tagged_addr_ctrl(unsigned long arg)
return -EINVAL;
if (system_supports_mte())
- valid_mask |= PR_MTE_TCF_MASK;
+ valid_mask |= PR_MTE_TCF_MASK | PR_MTE_TAG_MASK;
if (arg & ~valid_mask)
return -EINVAL;
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 2390ab324afa..7f0827705c9a 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -239,6 +239,9 @@ struct prctl_mm_map {
# define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
# define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT)
# define PR_MTE_TCF_MASK (3UL << PR_MTE_TCF_SHIFT)
+/* MTE tag inclusion mask */
+# define PR_MTE_TAG_SHIFT 3
+# define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT)
/* Control reclaim behavior when allocating memory */
#define PR_SET_IO_FLUSHER 57
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 18/19] arm64: mte: Kconfig entry
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (16 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 17/19] arm64: mte: Allow user control of the generated random tags " Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-02-26 18:05 ` [PATCH v2 19/19] arm64: mte: Add Memory Tagging Extension documentation Catalin Marinas
18 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
From: Vincenzo Frascino <vincenzo.frascino@arm.com>
Add Memory Tagging Extension support to the arm64 kbuild.
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Co-developed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm64/Kconfig | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 0b30e884e088..ed20f5b0e122 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1541,6 +1541,38 @@ config ARCH_RANDOM
endmenu
+menu "ARMv8.5 architectural features"
+
+config ARM64_AS_HAS_MTE
+ def_bool $(as-instr,.arch armv8.5-a+memtag)
+
+config ARM64_MTE
+ bool "Memory Tagging Extension support"
+ depends on ARM64_AS_HAS_MTE && ARM64_TAGGED_ADDR_ABI
+ select ARCH_USES_HIGH_VMA_FLAGS
+ select ARCH_NO_SWAP
+ help
+ Memory Tagging (part of the ARMv8.5 Extensions) provides
+ architectural support for run-time, always-on detection of
+ various classes of memory error to aid with software debugging
+ to eliminate vulnerabilities arising from memory-unsafe
+ languages.
+
+ This option enables the support for the Memory Tagging
+ Extension at EL0 (i.e. for userspace).
+
+ Selecting this option allows the feature to be detected at
+ runtime. Any secondary CPU not implementing this feature will
+ not be allowed a late bring-up.
+
+ Userspace binaries that want to use this feature must
+ explicitly opt in. The mechanism for the userspace is
+ described in:
+
+ Documentation/arm64/memory-tagging-extension.rst.
+
+endmenu
+
config ARM64_SVE
bool "ARM Scalable Vector Extension support"
default y
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v2 19/19] arm64: mte: Add Memory Tagging Extension documentation
2020-02-26 18:05 [PATCH v2 00/19] arm64: Memory Tagging Extension user-space support Catalin Marinas
` (17 preceding siblings ...)
2020-02-26 18:05 ` [PATCH v2 18/19] arm64: mte: Kconfig entry Catalin Marinas
@ 2020-02-26 18:05 ` Catalin Marinas
2020-03-09 14:30 ` Kevin Brodsky
2020-03-11 22:17 ` Richard Henderson
18 siblings, 2 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-02-26 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, Peter Collingbourne, linux-mm, Vincenzo Frascino,
Will Deacon
From: Vincenzo Frascino <vincenzo.frascino@arm.com>
Memory Tagging Extension (part of the ARMv8.5 Extensions) provides
a mechanism to detect the sources of memory related errors which
may be vulnerable to exploitation, including bounds violations,
use-after-free, use-after-return, use-out-of-scope and use before
initialization errors.
Add Memory Tagging Extension documentation for the arm64 linux
kernel support.
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Co-developed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
Notes:
v2:
- Documented the uaccess kernel tag checking mode.
- Removed the BTI definitions from cpu-feature-registers.rst.
- Removed the paragraph stating that MTE depends on the tagged address
ABI (while the Kconfig entry does, there is no requirement for the
user to enable both).
- Changed the GCR_EL1.Exclude handling description following the change
in the prctl() interface (include vs exclude mask).
- Updated the example code.
Documentation/arm64/cpu-feature-registers.rst | 2 +
Documentation/arm64/elf_hwcaps.rst | 5 +
Documentation/arm64/index.rst | 1 +
.../arm64/memory-tagging-extension.rst | 228 ++++++++++++++++++
4 files changed, 236 insertions(+)
create mode 100644 Documentation/arm64/memory-tagging-extension.rst
diff --git a/Documentation/arm64/cpu-feature-registers.rst b/Documentation/arm64/cpu-feature-registers.rst
index 41937a8091aa..b5679fa85ad9 100644
--- a/Documentation/arm64/cpu-feature-registers.rst
+++ b/Documentation/arm64/cpu-feature-registers.rst
@@ -174,6 +174,8 @@ infrastructure:
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
+ | MTE | [11-8] | y |
+ +------------------------------+---------+---------+
| SSBS | [7-4] | y |
+------------------------------+---------+---------+
diff --git a/Documentation/arm64/elf_hwcaps.rst b/Documentation/arm64/elf_hwcaps.rst
index 7dfb97dfe416..ca7f90e99e3a 100644
--- a/Documentation/arm64/elf_hwcaps.rst
+++ b/Documentation/arm64/elf_hwcaps.rst
@@ -236,6 +236,11 @@ HWCAP2_RNG
Functionality implied by ID_AA64ISAR0_EL1.RNDR == 0b0001.
+HWCAP2_MTE
+
+ Functionality implied by ID_AA64PFR1_EL1.MTE == 0b0010, as described
+ by Documentation/arm64/memory-tagging-extension.rst.
+
4. Unused AT_HWCAP bits
-----------------------
diff --git a/Documentation/arm64/index.rst b/Documentation/arm64/index.rst
index 5c0c69dc58aa..82970c6d384f 100644
--- a/Documentation/arm64/index.rst
+++ b/Documentation/arm64/index.rst
@@ -13,6 +13,7 @@ ARM64 Architecture
hugetlbpage
legacy_instructions
memory
+ memory-tagging-extension
pointer-authentication
silicon-errata
sve
diff --git a/Documentation/arm64/memory-tagging-extension.rst b/Documentation/arm64/memory-tagging-extension.rst
new file mode 100644
index 000000000000..00ac0e22d5e9
--- /dev/null
+++ b/Documentation/arm64/memory-tagging-extension.rst
@@ -0,0 +1,228 @@
+===============================================
+Memory Tagging Extension (MTE) in AArch64 Linux
+===============================================
+
+Authors: Vincenzo Frascino <vincenzo.frascino@arm.com>
+ Catalin Marinas <catalin.marinas@arm.com>
+
+Date: 2020-02-25
+
+This document describes the provision of the Memory Tagging Extension
+functionality in AArch64 Linux.
+
+Introduction
+============
+
+ARMv8.5 based processors introduce the Memory Tagging Extension (MTE)
+feature. MTE is built on top of the ARMv8.0 virtual address tagging TBI
+(Top Byte Ignore) feature and allows software to access a 4-bit
+allocation tag for each 16-byte granule in the physical address space.
+Such memory range must be mapped with the Normal-Tagged memory
+attribute. A logical tag is derived from bits 59-56 of the virtual
+address used for the memory access. A CPU with MTE enabled will compare
+the logical tag against the allocation tag and potentially raise an
+exception on mismatch, subject to system registers configuration.
+
+Userspace Support
+=================
+
+When ``CONFIG_ARM64_MTE`` is selected and Memory Tagging Extension is
+supported by the hardware, the kernel advertises the feature to
+userspace via ``HWCAP2_MTE``.
+
+PROT_MTE
+--------
+
+To access the allocation tags, a user process must enable the Tagged
+memory attribute on an address range using a new ``prot`` flag for
+``mmap()`` and ``mprotect()``:
+
+``PROT_MTE`` - Pages allow access to the MTE allocation tags.
+
+The allocation tag is set to 0 when such pages are first mapped in the
+user address space and preserved on copy-on-write. ``MAP_SHARED`` is
+supported and the allocation tags can be shared between processes.
+
+**Note**: ``PROT_MTE`` is only supported on ``MAP_ANONYMOUS`` and
+RAM-based file mappings (``tmpfs``, ``memfd``). Passing it to other
+types of mapping will result in ``-EINVAL`` returned by these system
+calls.
+
+**Note**: The ``PROT_MTE`` flag (and corresponding memory type) cannot
+be cleared by ``mprotect()``.
+
+Tag Check Faults
+----------------
+
+When ``PROT_MTE`` is enabled on an address range and a mismatch between
+the logical and allocation tags occurs on access, there are three
+configurable behaviours:
+
+- *Ignore* - This is the default mode. The CPU (and kernel) ignores the
+ tag check fault.
+
+- *Synchronous* - The kernel raises a ``SIGSEGV`` synchronously, with
+ ``.si_code = SEGV_MTESERR`` and ``.si_addr = <fault-address>``. The
+ memory access is not performed.
+
+- *Asynchronous* - The kernel raises a ``SIGSEGV``, in the current
+ thread, asynchronously following one or multiple tag check faults,
+ with ``.si_code = SEGV_MTEAERR`` and ``.si_addr = 0``.
+
+**Note**: There are no *match-all* logical tags available for user
+applications.
+
+The user can select the above modes, per thread, using the
+``prctl(PR_SET_TAGGED_ADDR_CTRL, flags, 0, 0, 0)`` system call where
+``flags`` contain one of the following values in the ``PR_MTE_TCF_MASK``
+bit-field:
+
+- ``PR_MTE_TCF_NONE`` - *Ignore* tag check faults
+- ``PR_MTE_TCF_SYNC`` - *Synchronous* tag check fault mode
+- ``PR_MTE_TCF_ASYNC`` - *Asynchronous* tag check fault mode
+
+Tag checking can also be disabled for a user thread by setting the
+``PSTATE.TCO`` bit with ``MSR TCO, #1``.
+
+**Note**: Signal handlers are always invoked with ``PSTATE.TCO = 0``,
+irrespective of the interrupted context.
+
+**Note**: Kernel accesses to user memory (e.g. ``read()`` system call)
+follow the same tag checking mode as set by the current thread.
+
+Excluding Tags in the ``IRG``, ``ADDG`` and ``SUBG`` instructions
+-----------------------------------------------------------------
+
+The architecture allows excluding certain tags to be randomly generated
+via the ``GCR_EL1.Exclude`` register bit-field. By default, Linux
+excludes all tags other than 0. A user thread can enable specific tags
+in the randomly generated set using the ``prctl(PR_SET_TAGGED_ADDR_CTRL,
+flags, 0, 0, 0)`` system call where ``flags`` contains the tags bitmap
+in the ``PR_MTE_TAG_MASK`` bit-field.
+
+**Note**: The hardware uses an exclude mask but the ``prctl()``
+interface provides an include mask.
+
+Example of correct usage
+========================
+
+*MTE Example code*
+
+.. code-block:: c
+
+ /*
+ * To be compiled with -march=armv8.5-a+memtag
+ */
+ #include <errno.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <sys/auxv.h>
+ #include <sys/mman.h>
+ #include <sys/prctl.h>
+
+ /*
+ * From arch/arm64/include/uapi/asm/hwcap.h
+ */
+ #define HWCAP2_MTE (1 << 18)
+
+ /*
+ * From arch/arm64/include/uapi/asm/mman.h
+ */
+ #define PROT_MTE 0x20
+
+ /*
+ * From include/uapi/linux/prctl.h
+ */
+ #define PR_SET_TAGGED_ADDR_CTRL 55
+ #define PR_GET_TAGGED_ADDR_CTRL 56
+ # define PR_TAGGED_ADDR_ENABLE (1UL << 0)
+ # define PR_MTE_TCF_SHIFT 1
+ # define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT)
+ # define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
+ # define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT)
+ # define PR_MTE_TCF_MASK (3UL << PR_MTE_TCF_SHIFT)
+ # define PR_MTE_TAG_SHIFT 3
+ # define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT)
+
+ /*
+ * Insert a random logical tag into the given pointer.
+ */
+ #define insert_random_tag(ptr) ({ \
+ __u64 __val; \
+ asm("irg %0, %1" : "=r" (__val) : "r" (ptr)); \
+ __val; \
+ })
+
+ /*
+ * Set the allocation tag on the destination address.
+ */
+ #define set_tag(tagged_addr) do { \
+ asm volatile("stg %0, [%0]" : : "r" (tagged_addr) : "memory"); \
+ } while (0)
+
+ int main()
+ {
+ unsigned long *a;
+ unsigned long page_sz = getpagesize();
+ unsigned long hwcap2 = getauxval(AT_HWCAP2);
+
+ /* check if MTE is present */
+ if (!(hwcap2 & HWCAP2_MTE))
+ return -1;
+
+ /*
+ * Enable the tagged address ABI, synchronous MTE tag check faults and
+ * allow all non-zero tags in the randomly generated set.
+ */
+ if (prctl(PR_SET_TAGGED_ADDR_CTRL,
+ PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | (0xfffe << PR_MTE_TAG_SHIFT),
+ 0, 0, 0)) {
+ perror("prctl() failed");
+ return -1;
+ }
+
+ a = mmap(0, page_sz, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (a == MAP_FAILED) {
+ perror("mmap() failed");
+ return -1;
+ }
+
+ /*
+ * Enable MTE on the above anonymous mmap. The flag could be passed
+ * directly to mmap() and skip this step.
+ */
+ if (mprotect(a, page_sz, PROT_READ | PROT_WRITE | PROT_MTE)) {
+ perror("mprotect() failed");
+ return -1;
+ }
+
+ /* access with the default tag (0) */
+ a[0] = 1;
+ a[1] = 2;
+
+ printf("a[0] = %lu a[1] = %lu\n", a[0], a[1]);
+
+ /* set the logical and allocation tags */
+ a = (unsigned long *)insert_random_tag(a);
+ set_tag(a);
+
+ printf("%p\n", a);
+
+ /* non-zero tag access */
+ a[0] = 3;
+ printf("a[0] = %lu a[1] = %lu\n", a[0], a[1]);
+
+ /*
+ * If MTE is enabled correctly the next instruction will generate an
+ * exception.
+ */
+ printf("Expecting SIGSEGV...\n");
+ a[2] = 0xdead;
+
+ /* this should not be printed in the PR_MTE_TCF_SYNC mode */
+ printf("...done\n");
+
+ return 0;
+ }
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v2 19/19] arm64: mte: Add Memory Tagging Extension documentation
2020-02-26 18:05 ` [PATCH v2 19/19] arm64: mte: Add Memory Tagging Extension documentation Catalin Marinas
@ 2020-03-09 14:30 ` Kevin Brodsky
2020-03-11 22:17 ` Richard Henderson
1 sibling, 0 replies; 32+ messages in thread
From: Kevin Brodsky @ 2020-03-09 14:30 UTC (permalink / raw)
To: Catalin Marinas, linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Szabolcs Nagy, Peter Collingbourne,
linux-mm, Andrey Konovalov, Vincenzo Frascino, Will Deacon
On 26/02/2020 18:05, Catalin Marinas wrote:
> From: Vincenzo Frascino <vincenzo.frascino@arm.com>
>
> Memory Tagging Extension (part of the ARMv8.5 Extensions) provides
> a mechanism to detect the sources of memory related errors which
> may be vulnerable to exploitation, including bounds violations,
> use-after-free, use-after-return, use-out-of-scope and use before
> initialization errors.
>
> Add Memory Tagging Extension documentation for the arm64 linux
> kernel support.
>
> Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
> Co-developed-by: Catalin Marinas <catalin.marinas@arm.com>
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> ---
>
> Notes:
> v2:
> - Documented the uaccess kernel tag checking mode.
> - Removed the BTI definitions from cpu-feature-registers.rst.
> - Removed the paragraph stating that MTE depends on the tagged address
> ABI (while the Kconfig entry does, there is no requirement for the
> user to enable both).
> - Changed the GCR_EL1.Exclude handling description following the change
> in the prctl() interface (include vs exclude mask).
> - Updated the example code.
>
> Documentation/arm64/cpu-feature-registers.rst | 2 +
> Documentation/arm64/elf_hwcaps.rst | 5 +
> Documentation/arm64/index.rst | 1 +
> .../arm64/memory-tagging-extension.rst | 228 ++++++++++++++++++
> 4 files changed, 236 insertions(+)
> create mode 100644 Documentation/arm64/memory-tagging-extension.rst
>
> diff --git a/Documentation/arm64/cpu-feature-registers.rst b/Documentation/arm64/cpu-feature-registers.rst
> index 41937a8091aa..b5679fa85ad9 100644
> --- a/Documentation/arm64/cpu-feature-registers.rst
> +++ b/Documentation/arm64/cpu-feature-registers.rst
> @@ -174,6 +174,8 @@ infrastructure:
> +------------------------------+---------+---------+
> | Name | bits | visible |
> +------------------------------+---------+---------+
> + | MTE | [11-8] | y |
> + +------------------------------+---------+---------+
> | SSBS | [7-4] | y |
> +------------------------------+---------+---------+
>
> diff --git a/Documentation/arm64/elf_hwcaps.rst b/Documentation/arm64/elf_hwcaps.rst
> index 7dfb97dfe416..ca7f90e99e3a 100644
> --- a/Documentation/arm64/elf_hwcaps.rst
> +++ b/Documentation/arm64/elf_hwcaps.rst
> @@ -236,6 +236,11 @@ HWCAP2_RNG
>
> Functionality implied by ID_AA64ISAR0_EL1.RNDR == 0b0001.
>
> +HWCAP2_MTE
> +
> + Functionality implied by ID_AA64PFR1_EL1.MTE == 0b0010, as described
> + by Documentation/arm64/memory-tagging-extension.rst.
> +
> 4. Unused AT_HWCAP bits
> -----------------------
>
> diff --git a/Documentation/arm64/index.rst b/Documentation/arm64/index.rst
> index 5c0c69dc58aa..82970c6d384f 100644
> --- a/Documentation/arm64/index.rst
> +++ b/Documentation/arm64/index.rst
> @@ -13,6 +13,7 @@ ARM64 Architecture
> hugetlbpage
> legacy_instructions
> memory
> + memory-tagging-extension
> pointer-authentication
> silicon-errata
> sve
> diff --git a/Documentation/arm64/memory-tagging-extension.rst b/Documentation/arm64/memory-tagging-extension.rst
> new file mode 100644
> index 000000000000..00ac0e22d5e9
> --- /dev/null
> +++ b/Documentation/arm64/memory-tagging-extension.rst
> @@ -0,0 +1,228 @@
> +===============================================
> +Memory Tagging Extension (MTE) in AArch64 Linux
> +===============================================
> +
> +Authors: Vincenzo Frascino <vincenzo.frascino@arm.com>
> + Catalin Marinas <catalin.marinas@arm.com>
> +
> +Date: 2020-02-25
> +
> +This document describes the provision of the Memory Tagging Extension
> +functionality in AArch64 Linux.
> +
> +Introduction
> +============
> +
> +ARMv8.5 based processors introduce the Memory Tagging Extension (MTE)
> +feature. MTE is built on top of the ARMv8.0 virtual address tagging TBI
> +(Top Byte Ignore) feature and allows software to access a 4-bit
> +allocation tag for each 16-byte granule in the physical address space.
> +Such memory range must be mapped with the Normal-Tagged memory
> +attribute. A logical tag is derived from bits 59-56 of the virtual
> +address used for the memory access. A CPU with MTE enabled will compare
> +the logical tag against the allocation tag and potentially raise an
> +exception on mismatch, subject to system registers configuration.
> +
> +Userspace Support
> +=================
> +
> +When ``CONFIG_ARM64_MTE`` is selected and Memory Tagging Extension is
> +supported by the hardware, the kernel advertises the feature to
> +userspace via ``HWCAP2_MTE``.
> +
> +PROT_MTE
> +--------
> +
> +To access the allocation tags, a user process must enable the Tagged
> +memory attribute on an address range using a new ``prot`` flag for
> +``mmap()`` and ``mprotect()``:
> +
> +``PROT_MTE`` - Pages allow access to the MTE allocation tags.
> +
> +The allocation tag is set to 0 when such pages are first mapped in the
> +user address space and preserved on copy-on-write. ``MAP_SHARED`` is
> +supported and the allocation tags can be shared between processes.
> +
> +**Note**: ``PROT_MTE`` is only supported on ``MAP_ANONYMOUS`` and
> +RAM-based file mappings (``tmpfs``, ``memfd``). Passing it to other
> +types of mapping will result in ``-EINVAL`` returned by these system
> +calls.
> +
> +**Note**: The ``PROT_MTE`` flag (and corresponding memory type) cannot
> +be cleared by ``mprotect()``.
> +
> +Tag Check Faults
> +----------------
> +
> +When ``PROT_MTE`` is enabled on an address range and a mismatch between
> +the logical and allocation tags occurs on access, there are three
> +configurable behaviours:
> +
> +- *Ignore* - This is the default mode. The CPU (and kernel) ignores the
> + tag check fault.
> +
> +- *Synchronous* - The kernel raises a ``SIGSEGV`` synchronously, with
> + ``.si_code = SEGV_MTESERR`` and ``.si_addr = <fault-address>``. The
> + memory access is not performed.
> +
> +- *Asynchronous* - The kernel raises a ``SIGSEGV``, in the current
> + thread, asynchronously following one or multiple tag check faults,
> + with ``.si_code = SEGV_MTEAERR`` and ``.si_addr = 0``.
> +
> +**Note**: There are no *match-all* logical tags available for user
> +applications.
> +
> +The user can select the above modes, per thread, using the
> +``prctl(PR_SET_TAGGED_ADDR_CTRL, flags, 0, 0, 0)`` system call where
> +``flags`` contain one of the following values in the ``PR_MTE_TCF_MASK``
> +bit-field:
> +
> +- ``PR_MTE_TCF_NONE`` - *Ignore* tag check faults
> +- ``PR_MTE_TCF_SYNC`` - *Synchronous* tag check fault mode
> +- ``PR_MTE_TCF_ASYNC`` - *Asynchronous* tag check fault mode
> +
> +Tag checking can also be disabled for a user thread by setting the
> +``PSTATE.TCO`` bit with ``MSR TCO, #1``.
> +
> +**Note**: Signal handlers are always invoked with ``PSTATE.TCO = 0``,
> +irrespective of the interrupted context.
> +
> +**Note**: Kernel accesses to user memory (e.g. ``read()`` system call)
> +follow the same tag checking mode as set by the current thread.
> +
> +Excluding Tags in the ``IRG``, ``ADDG`` and ``SUBG`` instructions
> +-----------------------------------------------------------------
> +
> +The architecture allows excluding certain tags to be randomly generated
> +via the ``GCR_EL1.Exclude`` register bit-field. By default, Linux
> +excludes all tags other than 0. A user thread can enable specific tags
> +in the randomly generated set using the ``prctl(PR_SET_TAGGED_ADDR_CTRL,
> +flags, 0, 0, 0)`` system call where ``flags`` contains the tags bitmap
> +in the ``PR_MTE_TAG_MASK`` bit-field.
> +
> +**Note**: The hardware uses an exclude mask but the ``prctl()``
> +interface provides an include mask.
Maybe it's worth mentioning that a tag mask of 0x0, or equivalently an exclusion mask
of 0xFFFF, results in the generated tag being always 0. This is not very clear even
in the Arm ARM, where this is only specified in the pseudocode (I shall report this
internally).
Kevin
> +
> +Example of correct usage
> +========================
> +
> +*MTE Example code*
> +
> +.. code-block:: c
> +
> + /*
> + * To be compiled with -march=armv8.5-a+memtag
> + */
> + #include <errno.h>
> + #include <stdio.h>
> + #include <stdlib.h>
> + #include <unistd.h>
> + #include <sys/auxv.h>
> + #include <sys/mman.h>
> + #include <sys/prctl.h>
> +
> + /*
> + * From arch/arm64/include/uapi/asm/hwcap.h
> + */
> + #define HWCAP2_MTE (1 << 18)
> +
> + /*
> + * From arch/arm64/include/uapi/asm/mman.h
> + */
> + #define PROT_MTE 0x20
> +
> + /*
> + * From include/uapi/linux/prctl.h
> + */
> + #define PR_SET_TAGGED_ADDR_CTRL 55
> + #define PR_GET_TAGGED_ADDR_CTRL 56
> + # define PR_TAGGED_ADDR_ENABLE (1UL << 0)
> + # define PR_MTE_TCF_SHIFT 1
> + # define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT)
> + # define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
> + # define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT)
> + # define PR_MTE_TCF_MASK (3UL << PR_MTE_TCF_SHIFT)
> + # define PR_MTE_TAG_SHIFT 3
> + # define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT)
> +
> + /*
> + * Insert a random logical tag into the given pointer.
> + */
> + #define insert_random_tag(ptr) ({ \
> + __u64 __val; \
> + asm("irg %0, %1" : "=r" (__val) : "r" (ptr)); \
> + __val; \
> + })
> +
> + /*
> + * Set the allocation tag on the destination address.
> + */
> + #define set_tag(tagged_addr) do { \
> + asm volatile("stg %0, [%0]" : : "r" (tagged_addr) : "memory"); \
> + } while (0)
> +
> + int main()
> + {
> + unsigned long *a;
> + unsigned long page_sz = getpagesize();
> + unsigned long hwcap2 = getauxval(AT_HWCAP2);
> +
> + /* check if MTE is present */
> + if (!(hwcap2 & HWCAP2_MTE))
> + return -1;
> +
> + /*
> + * Enable the tagged address ABI, synchronous MTE tag check faults and
> + * allow all non-zero tags in the randomly generated set.
> + */
> + if (prctl(PR_SET_TAGGED_ADDR_CTRL,
> + PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | (0xfffe << PR_MTE_TAG_SHIFT),
> + 0, 0, 0)) {
> + perror("prctl() failed");
> + return -1;
> + }
> +
> + a = mmap(0, page_sz, PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> + if (a == MAP_FAILED) {
> + perror("mmap() failed");
> + return -1;
> + }
> +
> + /*
> + * Enable MTE on the above anonymous mmap. The flag could be passed
> + * directly to mmap() and skip this step.
> + */
> + if (mprotect(a, page_sz, PROT_READ | PROT_WRITE | PROT_MTE)) {
> + perror("mprotect() failed");
> + return -1;
> + }
> +
> + /* access with the default tag (0) */
> + a[0] = 1;
> + a[1] = 2;
> +
> + printf("a[0] = %lu a[1] = %lu\n", a[0], a[1]);
> +
> + /* set the logical and allocation tags */
> + a = (unsigned long *)insert_random_tag(a);
> + set_tag(a);
> +
> + printf("%p\n", a);
> +
> + /* non-zero tag access */
> + a[0] = 3;
> + printf("a[0] = %lu a[1] = %lu\n", a[0], a[1]);
> +
> + /*
> + * If MTE is enabled correctly the next instruction will generate an
> + * exception.
> + */
> + printf("Expecting SIGSEGV...\n");
> + a[2] = 0xdead;
> +
> + /* this should not be printed in the PR_MTE_TCF_SYNC mode */
> + printf("...done\n");
> +
> + return 0;
> + }
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 19/19] arm64: mte: Add Memory Tagging Extension documentation
2020-02-26 18:05 ` [PATCH v2 19/19] arm64: mte: Add Memory Tagging Extension documentation Catalin Marinas
2020-03-09 14:30 ` Kevin Brodsky
@ 2020-03-11 22:17 ` Richard Henderson
2020-03-12 9:50 ` Catalin Marinas
1 sibling, 1 reply; 32+ messages in thread
From: Richard Henderson @ 2020-03-11 22:17 UTC (permalink / raw)
To: Catalin Marinas, linux-arm-kernel
Cc: linux-arch, Richard Earnshaw, Will Deacon, Szabolcs Nagy,
Andrey Konovalov, Kevin Brodsky, linux-mm, Vincenzo Frascino,
Peter Collingbourne
On 2/26/20 10:05 AM, Catalin Marinas wrote:
> + /*
> + * From include/uapi/linux/prctl.h
> + */
> + #define PR_SET_TAGGED_ADDR_CTRL 55
> + #define PR_GET_TAGGED_ADDR_CTRL 56
> + # define PR_TAGGED_ADDR_ENABLE (1UL << 0)
> + # define PR_MTE_TCF_SHIFT 1
> + # define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT)
> + # define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
> + # define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT)
> + # define PR_MTE_TCF_MASK (3UL << PR_MTE_TCF_SHIFT)
> + # define PR_MTE_TAG_SHIFT 3
> + # define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT)
Is there a reason not to include TCMA into the set of bits that userland can
control with this prcrl?
I know that ordinarily TCR_ELx requires expensive syncing, but for this
particular field there is a note about "software may change this control bit on
a context switch". Which I take to mean that the usual TLB-related syncing may
be omitted.
r~
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 19/19] arm64: mte: Add Memory Tagging Extension documentation
2020-03-11 22:17 ` Richard Henderson
@ 2020-03-12 9:50 ` Catalin Marinas
0 siblings, 0 replies; 32+ messages in thread
From: Catalin Marinas @ 2020-03-12 9:50 UTC (permalink / raw)
To: Richard Henderson
Cc: linux-arch, Richard Earnshaw, Will Deacon, Szabolcs Nagy,
Andrey Konovalov, Kevin Brodsky, linux-mm, Vincenzo Frascino,
Peter Collingbourne, linux-arm-kernel
On Wed, Mar 11, 2020 at 03:17:54PM -0700, Richard Henderson wrote:
> On 2/26/20 10:05 AM, Catalin Marinas wrote:
> > + /*
> > + * From include/uapi/linux/prctl.h
> > + */
> > + #define PR_SET_TAGGED_ADDR_CTRL 55
> > + #define PR_GET_TAGGED_ADDR_CTRL 56
> > + # define PR_TAGGED_ADDR_ENABLE (1UL << 0)
> > + # define PR_MTE_TCF_SHIFT 1
> > + # define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT)
> > + # define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
> > + # define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT)
> > + # define PR_MTE_TCF_MASK (3UL << PR_MTE_TCF_SHIFT)
> > + # define PR_MTE_TAG_SHIFT 3
> > + # define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT)
>
> Is there a reason not to include TCMA into the set of bits that userland can
> control with this prcrl?
>
> I know that ordinarily TCR_ELx requires expensive syncing, but for this
> particular field there is a note about "software may change this control bit on
> a context switch". Which I take to mean that the usual TLB-related syncing may
> be omitted.
TCMA (unlike TCF) is allowed to be cached in the TLB. If we are to allow
the user to configure this field, there are two approaches, each with
its own problems:
1. per-thread TCMA (as we do with TCF). Since the field is cached in the
TLB (ASID-tagged), we'd have to invalidate the TLB for that ASID
every time we switch between threads of the same process on a CPU.
2. per-process TCMA. This solves the problem of TLB invalidation,
however you'd have to synchronise all the threads that may run on
other CPUs. A simple IPI (as in sys_membarrier() for example) is not
sufficient since with CnP (CPU threads sharing the TLB) we'd need a
synchronous update. This leaves us with a stop_machine() call and I'm
not keen on exposing this to user via a syscall.
If you have a strong need for TCMA in user space, please raise it and we
can discuss about always allowing match-all tags for user tasks. Note
that the kernel will have match-all enabled for kernel addresses.
--
Catalin
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 32+ messages in thread