Commit 18107f8a authored by Vladimir Murzin's avatar Vladimir Murzin Committed by Catalin Marinas
Browse files

arm64: Support execute-only permissions with Enhanced PAN



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

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

Cc: Kees Cook <keescook@chromium.org>
Signed-off-by: default avatarVladimir Murzin <vladimir.murzin@arm.com>
Acked-by: default avatarWill Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20210312173811.58284-2-vladimir.murzin@arm.com


Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 1e28eed1
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -1058,6 +1058,9 @@ config SYS_SUPPORTS_HUGETLBFS
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

@@ -1681,6 +1684,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
+2 −1
Original line number Diff line number Diff line
@@ -66,7 +66,8 @@
#define ARM64_WORKAROUND_1508412		58
#define ARM64_HAS_LDAPR				59
#define ARM64_KVM_PROTECTED_MODE		60
#define ARM64_HAS_EPAN				61

#define ARM64_NCAPS				61
#define ARM64_NCAPS				62

#endif /* __ASM_CPUCAPS_H */
+3 −2
Original line number Diff line number Diff line
@@ -87,12 +87,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
@@ -101,7 +102,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
+23 −8
Original line number Diff line number Diff line
@@ -113,11 +113,12 @@ 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))
/*
 * Execute-only user mappings do not have the PTE_USER bit set. All valid
 * kernel mappings have the PTE_UXN bit set.
 */
#define pte_valid_not_user(pte) \
	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
#define pte_valid_user(pte) \
	((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))

	((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN))
/*
 * Could the pte be present in the TLB? We must check mm_tlb_flush_pending
 * so that we don't erroneously return false for pages that have been
@@ -130,12 +131,14 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
	(mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid(pte))

/*
 * p??_access_permitted() is true for valid user mappings (subject to the
 * write permission check). PROT_NONE mappings do not have the PTE_VALID bit
 * set.
 * p??_access_permitted() is true for valid user mappings (PTE_USER
 * bit set, subject to the write permission check). For execute-only
 * mappings, like PROT_EXEC with EPAN (both PTE_USER and PTE_UXN bits
 * not set) must return false. PROT_NONE mappings do not have the
 * PTE_VALID bit set.
 */
#define pte_access_permitted(pte, write) \
	(pte_valid_user(pte) && (!(write) || pte_write(pte)))
	(((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) && (!(write) || pte_write(pte)))
#define pmd_access_permitted(pmd, write) \
	(pte_access_permitted(pmd_pte(pmd), (write)))
#define pud_access_permitted(pud, write) \
@@ -995,6 +998,18 @@ static inline bool arch_wants_old_prefaulted_pte(void)
}
#define arch_wants_old_prefaulted_pte	arch_wants_old_prefaulted_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 */
+2 −1
Original line number Diff line number Diff line
@@ -597,6 +597,7 @@
	(SCTLR_EL2_RES1 | ENDIAN_SET_EL2)

/* SCTLR_EL1 specific flags. */
#define SCTLR_EL1_EPAN		(BIT(57))
#define SCTLR_EL1_ATA0		(BIT(42))

#define SCTLR_EL1_TCF0_SHIFT	38
@@ -637,7 +638,7 @@
	 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)
	 SCTLR_EL1_EPAN | SCTLR_EL1_RES1)

/* MAIR_ELx memory attributes (used by Linux) */
#define MAIR_ATTR_DEVICE_nGnRnE		UL(0x00)
Loading