All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/2]  arm64: Support Enhanced PAN
@ 2020-11-13 15:20 Vladimir Murzin
  2020-11-13 15:20 ` [RFC PATCH 1/2] arm64: Support execute-only permissions with " Vladimir Murzin
  2020-11-13 15:20 ` [RFC PATCH 2/2] arm64: Expose EPAN support via HWCAPS2_EPAN Vladimir Murzin
  0 siblings, 2 replies; 9+ messages in thread
From: Vladimir Murzin @ 2020-11-13 15:20 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: catalin.marinas, keescook

Hi

ARM architecture gains support of Enhanced Privileged Access Never
(EPAN) which allows Privileged Access Never to be used with
Execute-only mappings.

As a consequence 24cecc377463 ("arm64: Revert support for execute-only
user mappings") can be revisited and re-enabled.

Thanks!

Vladimir Murzin (2):
  arm64: Support execute-only permissions with Enhanced PAN
  arm64: Expose EPAN support via HWCAPS2_EPAN

 arch/arm64/Kconfig                    | 17 +++++++++++++++++
 arch/arm64/include/asm/cpucaps.h      |  3 ++-
 arch/arm64/include/asm/hwcap.h        |  1 +
 arch/arm64/include/asm/pgtable-prot.h |  5 +++--
 arch/arm64/include/asm/pgtable.h      | 23 +++++++++++++++++++++--
 arch/arm64/include/asm/sysreg.h       |  2 ++
 arch/arm64/include/uapi/asm/hwcap.h   |  1 +
 arch/arm64/kernel/cpufeature.c        | 23 +++++++++++++++++++++++
 arch/arm64/kernel/cpuinfo.c           |  1 +
 arch/arm64/mm/fault.c                 |  3 +++
 10 files changed, 74 insertions(+), 5 deletions(-)

-- 
2.7.4


_______________________________________________
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] 9+ messages in thread

* [RFC PATCH 1/2] arm64: Support execute-only permissions with Enhanced PAN
  2020-11-13 15:20 [RFC PATCH 0/2] arm64: Support Enhanced PAN Vladimir Murzin
@ 2020-11-13 15:20 ` Vladimir Murzin
  2020-11-17 16:47   ` Catalin Marinas
  2020-11-13 15:20 ` [RFC PATCH 2/2] arm64: Expose EPAN support via HWCAPS2_EPAN Vladimir Murzin
  1 sibling, 1 reply; 9+ messages in thread
From: Vladimir Murzin @ 2020-11-13 15:20 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: catalin.marinas, keescook

Enhanced Privileged Access Never (EPAN) allows Privileged Access Never
to be used with Execute-only mappings.

Absence of such support was a reason for 24cecc377463 ("arm64: Revert
support for execute-only user mappings"). Thus now it can be revisited
and re-enabled.

Cc: Kees Cook <keescook@chromium.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
---
 arch/arm64/Kconfig                    | 17 +++++++++++++++++
 arch/arm64/include/asm/cpucaps.h      |  3 ++-
 arch/arm64/include/asm/pgtable-prot.h |  5 +++--
 arch/arm64/include/asm/pgtable.h      | 23 +++++++++++++++++++++--
 arch/arm64/include/asm/sysreg.h       |  1 +
 arch/arm64/kernel/cpufeature.c        | 20 ++++++++++++++++++++
 arch/arm64/mm/fault.c                 |  3 +++
 7 files changed, 67 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 1515f6f..6639244 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1056,6 +1056,9 @@ config ARCH_WANT_HUGE_PMD_SHARE
 config ARCH_HAS_CACHE_LINE_SIZE
 	def_bool y
 
+config ARCH_HAS_FILTER_PGPROT
+	def_bool y
+
 config ARCH_ENABLE_SPLIT_PMD_PTLOCK
 	def_bool y if PGTABLE_LEVELS > 2
 
@@ -1688,6 +1691,20 @@ config ARM64_MTE
 
 endmenu
 
+menu "ARMv8.7 architectural features"
+
+config ARM64_EPAN
+	bool "Enable support for Enhanced Privileged Access Never (EPAN)"
+	default y
+	depends on ARM64_PAN
+	help
+	 Enhanced Privileged Access Never (EPAN) allows Privileged
+	 Access Never to be used with Execute-only mappings.
+
+	 The feature is detected at runtime, and will remain disabled
+	 if the cpu does not implement the feature.
+endmenu
+
 config ARM64_SVE
 	bool "ARM Scalable Vector Extension support"
 	default y
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index e7d9899..046202f 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -66,7 +66,8 @@
 #define ARM64_HAS_TLB_RANGE			56
 #define ARM64_MTE				57
 #define ARM64_WORKAROUND_1508412		58
+#define ARM64_HAS_EPAN				59
 
-#define ARM64_NCAPS				59
+#define ARM64_NCAPS				60
 
 #endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 046be78..f91c2aa 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -88,12 +88,13 @@ extern bool arm64_use_ng_mappings;
 #define PAGE_SHARED_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_WRITE)
 #define PAGE_READONLY		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
 #define PAGE_READONLY_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN)
+#define PAGE_EXECONLY		__pgprot(_PAGE_DEFAULT | PTE_RDONLY | PTE_NG | PTE_PXN)
 
 #define __P000  PAGE_NONE
 #define __P001  PAGE_READONLY
 #define __P010  PAGE_READONLY
 #define __P011  PAGE_READONLY
-#define __P100  PAGE_READONLY_EXEC
+#define __P100  PAGE_EXECONLY
 #define __P101  PAGE_READONLY_EXEC
 #define __P110  PAGE_READONLY_EXEC
 #define __P111  PAGE_READONLY_EXEC
@@ -102,7 +103,7 @@ extern bool arm64_use_ng_mappings;
 #define __S001  PAGE_READONLY
 #define __S010  PAGE_SHARED
 #define __S011  PAGE_SHARED
-#define __S100  PAGE_READONLY_EXEC
+#define __S100  PAGE_EXECONLY
 #define __S101  PAGE_READONLY_EXEC
 #define __S110  PAGE_SHARED_EXEC
 #define __S111  PAGE_SHARED_EXEC
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 4ff12a7..d1f68d2 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -113,8 +113,15 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
 #define pte_dirty(pte)		(pte_sw_dirty(pte) || pte_hw_dirty(pte))
 
 #define pte_valid(pte)		(!!(pte_val(pte) & PTE_VALID))
-#define pte_valid_not_user(pte) \
-	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
+#define pte_valid_not_user(pte)										\
+({													\
+	int __val;											\
+	if (cpus_have_const_cap(ARM64_HAS_EPAN))							\
+		__val = (pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN);	\
+	else												\
+		__val = (pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID;				\
+	__val;												\
+})
 #define pte_valid_young(pte) \
 	((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF))
 #define pte_valid_user(pte) \
@@ -974,6 +981,18 @@ static inline bool arch_faults_on_old_pte(void)
 }
 #define arch_faults_on_old_pte arch_faults_on_old_pte
 
+static inline pgprot_t arch_filter_pgprot(pgprot_t prot)
+{
+	if (cpus_have_const_cap(ARM64_HAS_EPAN))
+		return prot;
+
+	if (pgprot_val(prot) != pgprot_val(PAGE_EXECONLY))
+		return prot;
+
+	return PAGE_READONLY_EXEC;
+}
+
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __ASM_PGTABLE_H */
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 174817b..19147b6 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -579,6 +579,7 @@
 #endif
 
 /* SCTLR_EL1 specific flags. */
+#define SCTLR_EL1_EPAN		(BIT(57))
 #define SCTLR_EL1_ATA0		(BIT(42))
 
 #define SCTLR_EL1_TCF0_SHIFT	38
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index dcc165b..2033e0b 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1602,6 +1602,13 @@ static void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused)
 }
 #endif /* CONFIG_ARM64_PAN */
 
+#ifdef CONFIG_ARM64_EPAN
+static void cpu_enable_epan(const struct arm64_cpu_capabilities *__unused)
+{
+	sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_EPAN);
+}
+#endif /* CONFIG_ARM64_EPAN */
+
 #ifdef CONFIG_ARM64_RAS_EXTN
 static void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused)
 {
@@ -1750,6 +1757,19 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.cpu_enable = cpu_enable_pan,
 	},
 #endif /* CONFIG_ARM64_PAN */
+#ifdef CONFIG_ARM64_EPAN
+	{
+		.desc = "Enhanced Privileged Access Never",
+		.capability = ARM64_HAS_EPAN,
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.matches = has_cpuid_feature,
+		.sys_reg = SYS_ID_AA64MMFR1_EL1,
+		.field_pos = ID_AA64MMFR1_PAN_SHIFT,
+		.sign = FTR_UNSIGNED,
+		.min_field_value = 3,
+		.cpu_enable = cpu_enable_epan,
+	},
+#endif /* CONFIG_ARM64_EPAN */
 #ifdef CONFIG_ARM64_LSE_ATOMICS
 	{
 		.desc = "LSE atomic instructions",
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 1ee9400..b93222e 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -467,6 +467,9 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
 	if (faulthandler_disabled() || !mm)
 		goto no_context;
 
+	if (cpus_have_const_cap(ARM64_HAS_EPAN))
+		vm_flags &= ~VM_EXEC;
+
 	if (user_mode(regs))
 		mm_flags |= FAULT_FLAG_USER;
 
-- 
2.7.4


_______________________________________________
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] 9+ messages in thread

* [RFC PATCH 2/2] arm64: Expose EPAN support via HWCAPS2_EPAN
  2020-11-13 15:20 [RFC PATCH 0/2] arm64: Support Enhanced PAN Vladimir Murzin
  2020-11-13 15:20 ` [RFC PATCH 1/2] arm64: Support execute-only permissions with " Vladimir Murzin
@ 2020-11-13 15:20 ` Vladimir Murzin
  2020-11-17 16:59   ` Catalin Marinas
  1 sibling, 1 reply; 9+ messages in thread
From: Vladimir Murzin @ 2020-11-13 15:20 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: catalin.marinas, keescook

So user have a clue whether exec-only permissions will work.

Cc: Kees Cook <keescook@chromium.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
---
 arch/arm64/include/asm/hwcap.h      | 1 +
 arch/arm64/include/asm/sysreg.h     | 1 +
 arch/arm64/include/uapi/asm/hwcap.h | 1 +
 arch/arm64/kernel/cpufeature.c      | 3 +++
 arch/arm64/kernel/cpuinfo.c         | 1 +
 5 files changed, 7 insertions(+)

diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 9a5498c..6274c6c 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -105,6 +105,7 @@
 #define KERNEL_HWCAP_RNG		__khwcap2_feature(RNG)
 #define KERNEL_HWCAP_BTI		__khwcap2_feature(BTI)
 #define KERNEL_HWCAP_MTE		__khwcap2_feature(MTE)
+#define KERNEL_HWCAP_EPAN		__khwcap2_feature(EPAN)
 
 /*
  * This yields a mask that user programs can use to figure out what
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 19147b6..e7bc373 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -796,6 +796,7 @@
 
 #define ID_AA64MMFR1_VMIDBITS_8		0
 #define ID_AA64MMFR1_VMIDBITS_16	2
+#define ID_AA64MMFR1_EPAN		3
 
 /* id_aa64mmfr2 */
 #define ID_AA64MMFR2_E0PD_SHIFT		60
diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
index b8f41aa..a99da14 100644
--- a/arch/arm64/include/uapi/asm/hwcap.h
+++ b/arch/arm64/include/uapi/asm/hwcap.h
@@ -75,5 +75,6 @@
 #define HWCAP2_RNG		(1 << 16)
 #define HWCAP2_BTI		(1 << 17)
 #define HWCAP2_MTE		(1 << 18)
+#define HWCAP2_EPAN		(1 << 19)
 
 #endif /* _UAPI__ASM_HWCAP_H */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 2033e0b..bb2016c 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -2275,6 +2275,9 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
 #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 */
+#ifdef CONFIG_ARM64_EPAN
+	HWCAP_CAP(SYS_ID_AA64MMFR1_EL1, ID_AA64MMFR1_PAN_SHIFT, FTR_UNSIGNED, ID_AA64MMFR1_EPAN, CAP_HWCAP, KERNEL_HWCAP_EPAN),
+#endif
 	{},
 };
 
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 77605ae..9b69b13 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -94,6 +94,7 @@ static const char *const hwcap_str[] = {
 	[KERNEL_HWCAP_RNG]		= "rng",
 	[KERNEL_HWCAP_BTI]		= "bti",
 	[KERNEL_HWCAP_MTE]		= "mte",
+	[KERNEL_HWCAP_EPAN]		= "epan",
 };
 
 #ifdef CONFIG_COMPAT
-- 
2.7.4


_______________________________________________
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] 9+ messages in thread

* Re: [RFC PATCH 1/2] arm64: Support execute-only permissions with Enhanced PAN
  2020-11-13 15:20 ` [RFC PATCH 1/2] arm64: Support execute-only permissions with " Vladimir Murzin
@ 2020-11-17 16:47   ` Catalin Marinas
  2020-11-18 12:37     ` Vladimir Murzin
  0 siblings, 1 reply; 9+ messages in thread
From: Catalin Marinas @ 2020-11-17 16:47 UTC (permalink / raw)
  To: Vladimir Murzin; +Cc: keescook, linux-arm-kernel

On Fri, Nov 13, 2020 at 03:20:22PM +0000, Vladimir Murzin wrote:
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index 4ff12a7..d1f68d2 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -113,8 +113,15 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
>  #define pte_dirty(pte)		(pte_sw_dirty(pte) || pte_hw_dirty(pte))
>  
>  #define pte_valid(pte)		(!!(pte_val(pte) & PTE_VALID))
> -#define pte_valid_not_user(pte) \
> -	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
> +#define pte_valid_not_user(pte)										\
> +({													\
> +	int __val;											\
> +	if (cpus_have_const_cap(ARM64_HAS_EPAN))							\
> +		__val = (pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN);	\
> +	else												\
> +		__val = (pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID;				\
> +	__val;												\

Is it worth having the cap check here? I'd go with the PTE_VALID|PTE_UXN
check only.

> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index dcc165b..2033e0b 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -1602,6 +1602,13 @@ static void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused)
>  }
>  #endif /* CONFIG_ARM64_PAN */
>  
> +#ifdef CONFIG_ARM64_EPAN
> +static void cpu_enable_epan(const struct arm64_cpu_capabilities *__unused)
> +{
> +	sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_EPAN);
> +}
> +#endif /* CONFIG_ARM64_EPAN */

I checked the spec (2020 arch updates) and the EPAN bit is permitted to
be cached in the TLB. I think we get away with this because this
function is called before cnp is enabled. Maybe we should make it
explicit and move the CnP entry last with a comment.

-- 
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] 9+ messages in thread

* Re: [RFC PATCH 2/2] arm64: Expose EPAN support via HWCAPS2_EPAN
  2020-11-13 15:20 ` [RFC PATCH 2/2] arm64: Expose EPAN support via HWCAPS2_EPAN Vladimir Murzin
@ 2020-11-17 16:59   ` Catalin Marinas
  2020-11-18 12:43     ` Vladimir Murzin
  0 siblings, 1 reply; 9+ messages in thread
From: Catalin Marinas @ 2020-11-17 16:59 UTC (permalink / raw)
  To: Vladimir Murzin; +Cc: keescook, linux-arm-kernel

On Fri, Nov 13, 2020 at 03:20:23PM +0000, Vladimir Murzin wrote:
> So user have a clue whether exec-only permissions will work.

I do think we should tell user the PROT_EXEC actually gives execute-only
permission.

> --- a/arch/arm64/include/uapi/asm/hwcap.h
> +++ b/arch/arm64/include/uapi/asm/hwcap.h
> @@ -75,5 +75,6 @@
>  #define HWCAP2_RNG		(1 << 16)
>  #define HWCAP2_BTI		(1 << 17)
>  #define HWCAP2_MTE		(1 << 18)
> +#define HWCAP2_EPAN		(1 << 19)

However, I wonder whether EPAN is meaningful to the user. PAN is a
kernel protection that doesn't say much from a user perspective. Maybe
something like HWCAP2_EXECONLY?

That said, we do have a precedent on 32-bit where we exposed HWCAP_LPAE
to the user meaning that 64-bit atomics are available.

-- 
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] 9+ messages in thread

* Re: [RFC PATCH 1/2] arm64: Support execute-only permissions with Enhanced PAN
  2020-11-17 16:47   ` Catalin Marinas
@ 2020-11-18 12:37     ` Vladimir Murzin
  2020-11-18 16:04       ` Catalin Marinas
  0 siblings, 1 reply; 9+ messages in thread
From: Vladimir Murzin @ 2020-11-18 12:37 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: keescook, linux-arm-kernel

On 11/17/20 4:48 PM, Catalin Marinas wrote:
> On Fri, Nov 13, 2020 at 03:20:22PM +0000, Vladimir Murzin wrote:
>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>> index 4ff12a7..d1f68d2 100644
>> --- a/arch/arm64/include/asm/pgtable.h
>> +++ b/arch/arm64/include/asm/pgtable.h
>> @@ -113,8 +113,15 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
>>  #define pte_dirty(pte)		(pte_sw_dirty(pte) || pte_hw_dirty(pte))
>>  
>>  #define pte_valid(pte)		(!!(pte_val(pte) & PTE_VALID))
>> -#define pte_valid_not_user(pte) \
>> -	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
>> +#define pte_valid_not_user(pte)										\
>> +({													\
>> +	int __val;											\
>> +	if (cpus_have_const_cap(ARM64_HAS_EPAN))							\
>> +		__val = (pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN);	\
>> +	else												\
>> +		__val = (pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID;				\
>> +	__val;												\
> 
> Is it worth having the cap check here? I'd go with the PTE_VALID|PTE_UXN
> check only.
> 

I do not know to be honest. I do not have full picture in mind and what could be side effects of the
change (that's why RFC). 24cecc377463 the PTE_VALID|PTE_UXN moved to PTE_VALID, so I decided to be
safe than sorry...

>> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
>> index dcc165b..2033e0b 100644
>> --- a/arch/arm64/kernel/cpufeature.c
>> +++ b/arch/arm64/kernel/cpufeature.c
>> @@ -1602,6 +1602,13 @@ static void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused)
>>  }
>>  #endif /* CONFIG_ARM64_PAN */
>>  
>> +#ifdef CONFIG_ARM64_EPAN
>> +static void cpu_enable_epan(const struct arm64_cpu_capabilities *__unused)
>> +{
>> +	sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_EPAN);
>> +}
>> +#endif /* CONFIG_ARM64_EPAN */
> 
> I checked the spec (2020 arch updates) and the EPAN bit is permitted to
> be cached in the TLB. I think we get away with this because this
> function is called before cnp is enabled. Maybe we should make it
> explicit and move the CnP entry last with a comment.
> 

Hmm, so we rely on CnP's enable method to (indirectly) involve local_flush_tlb_all()? It doesn't seem
robust since CONFIG_ARM64_CNP could be unset. I can add local_flush_tlb_all() into cpu_enable_epan()
or we can have something like

diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index bb2016c..0f0a27b 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -2416,6 +2416,8 @@ static int cpu_enable_non_boot_scope_capabilities(void *__unused)
                if (cap->cpu_enable)
                        cap->cpu_enable(cap);
        }
+
+       local_flush_tlb_all();
        return 0;
 }
 
@@ -2467,6 +2469,8 @@ static void __init enable_cpu_capabilities(u16 scope_mask)
        if (!boot_scope)
                stop_machine(cpu_enable_non_boot_scope_capabilities,
                             NULL, cpu_online_mask);
+       else
+               local_flush_tlb_all();
 }
 
 /*

What would be your preference?

Cheers
Vladimir

_______________________________________________
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] 9+ messages in thread

* Re: [RFC PATCH 2/2] arm64: Expose EPAN support via HWCAPS2_EPAN
  2020-11-17 16:59   ` Catalin Marinas
@ 2020-11-18 12:43     ` Vladimir Murzin
  0 siblings, 0 replies; 9+ messages in thread
From: Vladimir Murzin @ 2020-11-18 12:43 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: keescook, linux-arm-kernel

On 11/17/20 4:59 PM, Catalin Marinas wrote:
> On Fri, Nov 13, 2020 at 03:20:23PM +0000, Vladimir Murzin wrote:
>> So user have a clue whether exec-only permissions will work.
> 
> I do think we should tell user the PROT_EXEC actually gives execute-only
> permission.

Ack.

> 
>> --- a/arch/arm64/include/uapi/asm/hwcap.h
>> +++ b/arch/arm64/include/uapi/asm/hwcap.h
>> @@ -75,5 +75,6 @@
>>  #define HWCAP2_RNG		(1 << 16)
>>  #define HWCAP2_BTI		(1 << 17)
>>  #define HWCAP2_MTE		(1 << 18)
>> +#define HWCAP2_EPAN		(1 << 19)
> 
> However, I wonder whether EPAN is meaningful to the user. PAN is a
> kernel protection that doesn't say much from a user perspective. Maybe
> something like HWCAP2_EXECONLY?

Works for me.

> 
> That said, we do have a precedent on 32-bit where we exposed HWCAP_LPAE
> to the user meaning that 64-bit atomics are available.
> 

It doesn't mean we have to follow it :)

Cheers
Vladimir

_______________________________________________
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] 9+ messages in thread

* Re: [RFC PATCH 1/2] arm64: Support execute-only permissions with Enhanced PAN
  2020-11-18 12:37     ` Vladimir Murzin
@ 2020-11-18 16:04       ` Catalin Marinas
  2020-11-19 13:39         ` Vladimir Murzin
  0 siblings, 1 reply; 9+ messages in thread
From: Catalin Marinas @ 2020-11-18 16:04 UTC (permalink / raw)
  To: Vladimir Murzin; +Cc: keescook, linux-arm-kernel

On Wed, Nov 18, 2020 at 12:37:40PM +0000, Vladimir Murzin wrote:
> On 11/17/20 4:48 PM, Catalin Marinas wrote:
> > On Fri, Nov 13, 2020 at 03:20:22PM +0000, Vladimir Murzin wrote:
> >> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> >> index 4ff12a7..d1f68d2 100644
> >> --- a/arch/arm64/include/asm/pgtable.h
> >> +++ b/arch/arm64/include/asm/pgtable.h
> >> @@ -113,8 +113,15 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
> >>  #define pte_dirty(pte)		(pte_sw_dirty(pte) || pte_hw_dirty(pte))
> >>  
> >>  #define pte_valid(pte)		(!!(pte_val(pte) & PTE_VALID))
> >> -#define pte_valid_not_user(pte) \
> >> -	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
> >> +#define pte_valid_not_user(pte)										\
> >> +({													\
> >> +	int __val;											\
> >> +	if (cpus_have_const_cap(ARM64_HAS_EPAN))							\
> >> +		__val = (pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN);	\
> >> +	else												\
> >> +		__val = (pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID;				\
> >> +	__val;												\
> > 
> > Is it worth having the cap check here? I'd go with the PTE_VALID|PTE_UXN
> > check only.
> 
> I do not know to be honest. I do not have full picture in mind and
> what could be side effects of the change (that's why RFC).
> 24cecc377463 the PTE_VALID|PTE_UXN moved to PTE_VALID, so I decided to
> be safe than sorry...

A user has access to a page if it has PTE_VALID && (PTE_USER || !PTE_UXN)
(wrong user of the logic operators but you get the idea). So negating
the user part in the above expression, pte_valid_not_user() means
PTE_VALID && !PTE_USER && PTE_UXN.

Prior to these patches (or the old exec-only), we can't have PTE_UXN and
PTE_USER both cleared, this is introduced by PAGE_EXECONLY. IOW, without
EPAN, !PTE_USER implies PTE_UXN, so we can use the same check as for the
EPAN case.

> >> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> >> index dcc165b..2033e0b 100644
> >> --- a/arch/arm64/kernel/cpufeature.c
> >> +++ b/arch/arm64/kernel/cpufeature.c
> >> @@ -1602,6 +1602,13 @@ static void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused)
> >>  }
> >>  #endif /* CONFIG_ARM64_PAN */
> >>  
> >> +#ifdef CONFIG_ARM64_EPAN
> >> +static void cpu_enable_epan(const struct arm64_cpu_capabilities *__unused)
> >> +{
> >> +	sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_EPAN);
> >> +}
> >> +#endif /* CONFIG_ARM64_EPAN */
> > 
> > I checked the spec (2020 arch updates) and the EPAN bit is permitted to
> > be cached in the TLB. I think we get away with this because this
> > function is called before cnp is enabled. Maybe we should make it
> > explicit and move the CnP entry last with a comment.
> 
> Hmm, so we rely on CnP's enable method to (indirectly) involve
> local_flush_tlb_all()? It doesn't seem robust since CONFIG_ARM64_CNP
> could be unset. I can add local_flush_tlb_all() into cpu_enable_epan()
> or we can have something like

A local_flush_tlb_all() in cpu_enable_epan() would be fine before user
space starts. However, a late CPU bring-up may cause a temporary
disabling of EPAN in the sibling core if CnP is enabled first.

> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index bb2016c..0f0a27b 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -2416,6 +2416,8 @@ static int cpu_enable_non_boot_scope_capabilities(void *__unused)
>                 if (cap->cpu_enable)
>                         cap->cpu_enable(cap);
>         }
> +
> +       local_flush_tlb_all();
>         return 0;
>  }
>  
> @@ -2467,6 +2469,8 @@ static void __init enable_cpu_capabilities(u16 scope_mask)
>         if (!boot_scope)
>                 stop_machine(cpu_enable_non_boot_scope_capabilities,
>                              NULL, cpu_online_mask);
> +       else
> +               local_flush_tlb_all();
>  }

Any local TLBI would clear the mismatch but it doesn't solve the
temporary difference between sibling cores. I think the only guarantee
here is if CnP is turned on after the feature in question.

-- 
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] 9+ messages in thread

* Re: [RFC PATCH 1/2] arm64: Support execute-only permissions with Enhanced PAN
  2020-11-18 16:04       ` Catalin Marinas
@ 2020-11-19 13:39         ` Vladimir Murzin
  0 siblings, 0 replies; 9+ messages in thread
From: Vladimir Murzin @ 2020-11-19 13:39 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: keescook, linux-arm-kernel

On 11/18/20 4:04 PM, Catalin Marinas wrote:
> On Wed, Nov 18, 2020 at 12:37:40PM +0000, Vladimir Murzin wrote:
>> On 11/17/20 4:48 PM, Catalin Marinas wrote:
>>> On Fri, Nov 13, 2020 at 03:20:22PM +0000, Vladimir Murzin wrote:
>>>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>>>> index 4ff12a7..d1f68d2 100644
>>>> --- a/arch/arm64/include/asm/pgtable.h
>>>> +++ b/arch/arm64/include/asm/pgtable.h
>>>> @@ -113,8 +113,15 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
>>>>  #define pte_dirty(pte)		(pte_sw_dirty(pte) || pte_hw_dirty(pte))
>>>>  
>>>>  #define pte_valid(pte)		(!!(pte_val(pte) & PTE_VALID))
>>>> -#define pte_valid_not_user(pte) \
>>>> -	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
>>>> +#define pte_valid_not_user(pte)										\
>>>> +({													\
>>>> +	int __val;											\
>>>> +	if (cpus_have_const_cap(ARM64_HAS_EPAN))							\
>>>> +		__val = (pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN);	\
>>>> +	else												\
>>>> +		__val = (pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID;				\
>>>> +	__val;												\
>>>
>>> Is it worth having the cap check here? I'd go with the PTE_VALID|PTE_UXN
>>> check only.
>>
>> I do not know to be honest. I do not have full picture in mind and
>> what could be side effects of the change (that's why RFC).
>> 24cecc377463 the PTE_VALID|PTE_UXN moved to PTE_VALID, so I decided to
>> be safe than sorry...
> 
> A user has access to a page if it has PTE_VALID && (PTE_USER || !PTE_UXN)
> (wrong user of the logic operators but you get the idea). So negating
> the user part in the above expression, pte_valid_not_user() means
> PTE_VALID && !PTE_USER && PTE_UXN.
> 
> Prior to these patches (or the old exec-only), we can't have PTE_UXN and
> PTE_USER both cleared, this is introduced by PAGE_EXECONLY. IOW, without
> EPAN, !PTE_USER implies PTE_UXN, so we can use the same check as for the
> EPAN case.
> 
>>>> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
>>>> index dcc165b..2033e0b 100644
>>>> --- a/arch/arm64/kernel/cpufeature.c
>>>> +++ b/arch/arm64/kernel/cpufeature.c
>>>> @@ -1602,6 +1602,13 @@ static void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused)
>>>>  }
>>>>  #endif /* CONFIG_ARM64_PAN */
>>>>  
>>>> +#ifdef CONFIG_ARM64_EPAN
>>>> +static void cpu_enable_epan(const struct arm64_cpu_capabilities *__unused)
>>>> +{
>>>> +	sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_EPAN);
>>>> +}
>>>> +#endif /* CONFIG_ARM64_EPAN */
>>>
>>> I checked the spec (2020 arch updates) and the EPAN bit is permitted to
>>> be cached in the TLB. I think we get away with this because this
>>> function is called before cnp is enabled. Maybe we should make it
>>> explicit and move the CnP entry last with a comment.
>>
>> Hmm, so we rely on CnP's enable method to (indirectly) involve
>> local_flush_tlb_all()? It doesn't seem robust since CONFIG_ARM64_CNP
>> could be unset. I can add local_flush_tlb_all() into cpu_enable_epan()
>> or we can have something like
> 
> A local_flush_tlb_all() in cpu_enable_epan() would be fine before user
> space starts. However, a late CPU bring-up may cause a temporary
> disabling of EPAN in the sibling core if CnP is enabled first.
> 
>> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
>> index bb2016c..0f0a27b 100644
>> --- a/arch/arm64/kernel/cpufeature.c
>> +++ b/arch/arm64/kernel/cpufeature.c
>> @@ -2416,6 +2416,8 @@ static int cpu_enable_non_boot_scope_capabilities(void *__unused)
>>                 if (cap->cpu_enable)
>>                         cap->cpu_enable(cap);
>>         }
>> +
>> +       local_flush_tlb_all();
>>         return 0;
>>  }
>>  
>> @@ -2467,6 +2469,8 @@ static void __init enable_cpu_capabilities(u16 scope_mask)
>>         if (!boot_scope)
>>                 stop_machine(cpu_enable_non_boot_scope_capabilities,
>>                              NULL, cpu_online_mask);
>> +       else
>> +               local_flush_tlb_all();
>>  }
> 
> Any local TLBI would clear the mismatch but it doesn't solve the
> temporary difference between sibling cores. I think the only guarantee
> here is if CnP is turned on after the feature in question.
> 

Thanks for explanation, I'll send updated version shortly!

Cheers
Vladimir

_______________________________________________
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] 9+ messages in thread

end of thread, other threads:[~2020-11-19 13:39 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-13 15:20 [RFC PATCH 0/2] arm64: Support Enhanced PAN Vladimir Murzin
2020-11-13 15:20 ` [RFC PATCH 1/2] arm64: Support execute-only permissions with " Vladimir Murzin
2020-11-17 16:47   ` Catalin Marinas
2020-11-18 12:37     ` Vladimir Murzin
2020-11-18 16:04       ` Catalin Marinas
2020-11-19 13:39         ` Vladimir Murzin
2020-11-13 15:20 ` [RFC PATCH 2/2] arm64: Expose EPAN support via HWCAPS2_EPAN Vladimir Murzin
2020-11-17 16:59   ` Catalin Marinas
2020-11-18 12:43     ` Vladimir Murzin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.