Make KUAP/KUEP key a variable and also check whether the platform limit the max key such that we can't use the key for KUAP/KEUP.
Signed-off-by: Aneesh Kumar K.V <aneesh.ku...@linux.ibm.com> --- .../powerpc/include/asm/book3s/64/hash-pkey.h | 22 +-------- arch/powerpc/include/asm/book3s/64/kup.h | 1 + arch/powerpc/mm/book3s64/pkeys.c | 46 +++++++++++++++++-- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/hash-pkey.h b/arch/powerpc/include/asm/book3s/64/hash-pkey.h index 9f44e208f036..ff9907c72ee3 100644 --- a/arch/powerpc/include/asm/book3s/64/hash-pkey.h +++ b/arch/powerpc/include/asm/book3s/64/hash-pkey.h @@ -2,9 +2,7 @@ #ifndef _ASM_POWERPC_BOOK3S_64_HASH_PKEY_H #define _ASM_POWERPC_BOOK3S_64_HASH_PKEY_H -/* We use key 3 for KERNEL */ -#define HASH_DEFAULT_KERNEL_KEY (HPTE_R_KEY_BIT0 | HPTE_R_KEY_BIT1) - +u64 pte_to_hpte_pkey_bits(u64 pteflags, unsigned long flags); static inline u64 hash__vmflag_to_pte_pkey_bits(u64 vm_flags) { return (((vm_flags & VM_PKEY_BIT0) ? H_PTE_PKEY_BIT0 : 0x0UL) | @@ -14,24 +12,6 @@ static inline u64 hash__vmflag_to_pte_pkey_bits(u64 vm_flags) ((vm_flags & VM_PKEY_BIT4) ? H_PTE_PKEY_BIT4 : 0x0UL)); } -static inline u64 pte_to_hpte_pkey_bits(u64 pteflags, unsigned long flags) -{ - unsigned long pte_pkey; - - pte_pkey = (((pteflags & H_PTE_PKEY_BIT4) ? HPTE_R_KEY_BIT4 : 0x0UL) | - ((pteflags & H_PTE_PKEY_BIT3) ? HPTE_R_KEY_BIT3 : 0x0UL) | - ((pteflags & H_PTE_PKEY_BIT2) ? HPTE_R_KEY_BIT2 : 0x0UL) | - ((pteflags & H_PTE_PKEY_BIT1) ? HPTE_R_KEY_BIT1 : 0x0UL) | - ((pteflags & H_PTE_PKEY_BIT0) ? HPTE_R_KEY_BIT0 : 0x0UL)); - - if (mmu_has_feature(MMU_FTR_KUAP) || mmu_has_feature(MMU_FTR_KUEP)) { - if ((pte_pkey == 0) && (flags & HPTE_USE_KERNEL_KEY)) - return HASH_DEFAULT_KERNEL_KEY; - } - - return pte_pkey; -} - static inline u16 hash__pte_to_pkey_bits(u64 pteflags) { return (((pteflags & H_PTE_PKEY_BIT4) ? 0x10 : 0x0UL) | diff --git a/arch/powerpc/include/asm/book3s/64/kup.h b/arch/powerpc/include/asm/book3s/64/kup.h index be04733c89f3..42ed67ec4e64 100644 --- a/arch/powerpc/include/asm/book3s/64/kup.h +++ b/arch/powerpc/include/asm/book3s/64/kup.h @@ -172,6 +172,7 @@ extern u64 default_uamor; extern u64 default_amr; extern u64 default_iamr; +extern int kup_key; /* * For kernel thread that doesn't have thread.regs return diff --git a/arch/powerpc/mm/book3s64/pkeys.c b/arch/powerpc/mm/book3s64/pkeys.c index 65dbb335f0a0..9fb90ceef08b 100644 --- a/arch/powerpc/mm/book3s64/pkeys.c +++ b/arch/powerpc/mm/book3s64/pkeys.c @@ -30,6 +30,10 @@ u64 default_uamor = ~0x0UL; * We pick key 2 because 0 is special key and 1 is reserved as per ISA. */ static int execute_only_key = 2; +/* + * key used to implement KUAP/KUEP with hash translation. + */ +int kup_key = 3; #define AMR_BITS_PER_PKEY 2 @@ -170,6 +174,18 @@ void __init pkey_early_init_devtree(void) default_uamor &= ~(0x3ul << pkeyshift(execute_only_key)); } + if (unlikely(max_pkey <= kup_key)) { + /* + * Insufficient number of keys to support + * KUAP/KUEP feature. + */ + kup_key = -1; + } else { + /* handle key which is used by kernel for KAUP */ + reserved_allocation_mask |= (0x1 << kup_key); + default_uamor &= ~(0x3ul << pkeyshift(kup_key)); + } + /* * Allow access for only key 0. And prevent any other modification. */ @@ -190,9 +206,6 @@ void __init pkey_early_init_devtree(void) reserved_allocation_mask |= (0x1 << 1); default_uamor &= ~(0x3ul << pkeyshift(1)); - /* handle key 3 which is used by kernel for KAUP */ - reserved_allocation_mask |= (0x1 << 3); - default_uamor &= ~(0x3ul << pkeyshift(3)); /* * Prevent the usage of OS reserved keys. Update UAMOR @@ -221,7 +234,7 @@ void __init pkey_early_init_devtree(void) #ifdef CONFIG_PPC_KUEP void __init setup_kuep(bool disabled) { - if (disabled) + if (disabled || kup_key == -1) return; /* * On hash if PKEY feature is not enabled, disable KUAP too. @@ -247,7 +260,7 @@ void __init setup_kuep(bool disabled) #ifdef CONFIG_PPC_KUAP void __init setup_kuap(bool disabled) { - if (disabled) + if (disabled || kup_key == -1) return; /* * On hash if PKEY feature is not enabled, disable KUAP too. @@ -450,3 +463,26 @@ void arch_dup_pkeys(struct mm_struct *oldmm, struct mm_struct *mm) mm_pkey_allocation_map(mm) = mm_pkey_allocation_map(oldmm); mm->context.execute_only_pkey = oldmm->context.execute_only_pkey; } + +u64 pte_to_hpte_pkey_bits(u64 pteflags, unsigned long flags) +{ + unsigned long pte_pkey; + + pte_pkey = (((pteflags & H_PTE_PKEY_BIT4) ? HPTE_R_KEY_BIT4 : 0x0UL) | + ((pteflags & H_PTE_PKEY_BIT3) ? HPTE_R_KEY_BIT3 : 0x0UL) | + ((pteflags & H_PTE_PKEY_BIT2) ? HPTE_R_KEY_BIT2 : 0x0UL) | + ((pteflags & H_PTE_PKEY_BIT1) ? HPTE_R_KEY_BIT1 : 0x0UL) | + ((pteflags & H_PTE_PKEY_BIT0) ? HPTE_R_KEY_BIT0 : 0x0UL)); + + if (mmu_has_feature(MMU_FTR_KUAP) || mmu_has_feature(MMU_FTR_KUEP)) { + if ((pte_pkey == 0) && + (flags & HPTE_USE_KERNEL_KEY) && (kup_key != -1)) { + u64 vm_flag = pkey_to_vmflag_bits(kup_key); + u64 pte_flag = hash__vmflag_to_pte_pkey_bits(vm_flag); + return pte_to_hpte_pkey_bits(pte_flag, 0); + } + } + + return pte_pkey; +} + -- 2.26.2