int num_pkey; /* Max number of pkeys supported */ /* * Keys marked in the reservation list cannot be allocated by userspace
*/
u32 reserved_allocation_mask __ro_after_init;
/* Bits set for the initially allocated keys */ static u32 initial_allocation_mask __ro_after_init;
/* * Even if we allocate keys with sys_pkey_alloc(), we need to make sure * other thread still find the access denied using the same keys.
*/
u64 default_amr __ro_after_init = ~0x0UL;
u64 default_iamr __ro_after_init = 0x5555555555555555UL;
u64 default_uamor __ro_after_init;
EXPORT_SYMBOL(default_amr); /* * Key used to implement PROT_EXEC mmap. Denies READ/WRITE * We pick key 2 because 0 is special key and 1 is reserved as per ISA.
*/ staticint execute_only_key = 2; staticbool pkey_execute_disable_supported;
staticint __init scan_pkey_feature(void)
{ int ret; int pkeys_total = 0;
/* * Pkey is not supported with Radix translation.
*/ if (early_radix_enabled()) return 0;
ret = of_scan_flat_dt(dt_scan_storage_keys, &pkeys_total); if (ret == 0) { /* * Let's assume 32 pkeys on P8/P9 bare metal, if its not defined by device * tree. We make this exception since some version of skiboot forgot to * expose this property on power8/9.
*/ if (!firmware_has_feature(FW_FEATURE_LPAR)) { unsignedlong pvr = mfspr(SPRN_PVR);
#ifdef CONFIG_PPC_MEM_KEYS /* * Adjust the upper limit, based on the number of bits supported by * arch-neutral code.
*/
pkeys_total = min_t(int, pkeys_total,
((ARCH_VM_PKEY_FLAGS >> VM_PKEY_SHIFT) + 1)); #endif return pkeys_total;
}
void __init pkey_early_init_devtree(void)
{ int pkeys_total, i;
#ifdef CONFIG_PPC_MEM_KEYS /* * We define PKEY_DISABLE_EXECUTE in addition to the arch-neutral * generic defines for PKEY_DISABLE_ACCESS and PKEY_DISABLE_WRITE. * Ensure that the bits a distinct.
*/
BUILD_BUG_ON(PKEY_DISABLE_EXECUTE &
(PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));
/* * pkey_to_vmflag_bits() assumes that the pkey bits are contiguous * in the vmaflag. Make sure that is really the case.
*/
BUILD_BUG_ON(__builtin_clzl(ARCH_VM_PKEY_FLAGS >> VM_PKEY_SHIFT) +
__builtin_popcountl(ARCH_VM_PKEY_FLAGS >> VM_PKEY_SHIFT)
!= (sizeof(u64) * BITS_PER_BYTE)); #endif /* * Only P7 and above supports SPRN_AMR update with MSR[PR] = 1
*/ if (!early_cpu_has_feature(CPU_FTR_ARCH_206)) return;
/* scan the device tree for pkey feature */
pkeys_total = scan_pkey_feature(); if (!pkeys_total) goto out;
/* Allow all keys to be modified by default */
default_uamor = ~0x0UL;
cur_cpu_spec->mmu_features |= MMU_FTR_PKEY;
/* * The device tree cannot be relied to indicate support for * execute_disable support. Instead we use a PVR check.
*/ if (pvr_version_is(PVR_POWER7) || pvr_version_is(PVR_POWER7p))
pkey_execute_disable_supported = false; else
pkey_execute_disable_supported = true;
#ifdef CONFIG_PPC_4K_PAGES /* * The OS can manage only 8 pkeys due to its inability to represent them * in the Linux 4K PTE. Mark all other keys reserved.
*/
num_pkey = min(8, pkeys_total); #else
num_pkey = pkeys_total; #endif
if (unlikely(num_pkey <= execute_only_key) || !pkey_execute_disable_supported) { /* * Insufficient number of keys to support * execute only key. Mark it unavailable.
*/
execute_only_key = -1;
} else { /* * Mark the execute_only_pkey as not available for * user allocation via pkey_alloc.
*/
reserved_allocation_mask |= (0x1 << execute_only_key);
/* * Clear the uamor bits for this key.
*/
default_uamor &= ~(0x3ul << pkeyshift(execute_only_key));
}
if (unlikely(num_pkey <= 3)) { /* * Insufficient number of keys to support * KUAP/KUEP feature.
*/
disable_kuep = true;
disable_kuap = true;
WARN(1, "Disabling kernel user protection due to low (%d) max supported keys\n", num_pkey);
} else { /* handle key which is used by kernel for KAUP */
reserved_allocation_mask |= (0x1 << 3); /* * Mark access for kup_key in default amr so that * we continue to operate with that AMR in * copy_to/from_user().
*/
default_amr &= ~(0x3ul << pkeyshift(3));
default_iamr &= ~(0x1ul << pkeyshift(3));
default_uamor &= ~(0x3ul << pkeyshift(3));
}
/* * Allow access for only key 0. And prevent any other modification.
*/
default_amr &= ~(0x3ul << pkeyshift(0));
default_iamr &= ~(0x1ul << pkeyshift(0));
default_uamor &= ~(0x3ul << pkeyshift(0)); /* * key 0 is special in that we want to consider it an allocated * key which is preallocated. We don't allow changing AMR bits * w.r.t key 0. But one can pkey_free(key0)
*/
initial_allocation_mask |= (0x1 << 0);
/* * key 1 is recommended not to be used. PowerISA(3.0) page 1015, * programming note.
*/
reserved_allocation_mask |= (0x1 << 1);
default_uamor &= ~(0x3ul << pkeyshift(1));
/* * Prevent the usage of OS reserved keys. Update UAMOR * for those keys. Also mark the rest of the bits in the * 32 bit mask as reserved.
*/ for (i = num_pkey; i < 32 ; i++) {
reserved_allocation_mask |= (0x1 << i);
default_uamor &= ~(0x3ul << pkeyshift(i));
} /* * Prevent the allocation of reserved keys too.
*/
initial_allocation_mask |= reserved_allocation_mask;
pr_info("Enabling pkeys with max key count %d\n", num_pkey);
out: /* * Setup uamor on boot cpu
*/
mtspr(SPRN_UAMOR, default_uamor);
return;
}
#ifdef CONFIG_PPC_KUEP void setup_kuep(bool disabled)
{ if (disabled) return; /* * On hash if PKEY feature is not enabled, disable KUAP too.
*/ if (!early_radix_enabled() && !early_mmu_has_feature(MMU_FTR_PKEY)) return;
/* * Radix always uses key0 of the IAMR to determine if an access is * allowed. We set bit 0 (IBM bit 1) of key0, to prevent instruction * fetch.
*/
mtspr(SPRN_IAMR, AMR_KUEP_BLOCKED);
isync();
} #endif
#ifdef CONFIG_PPC_KUAP void setup_kuap(bool disabled)
{ if (disabled) return; /* * On hash if PKEY feature is not enabled, disable KUAP too.
*/ if (!early_radix_enabled() && !early_mmu_has_feature(MMU_FTR_PKEY)) return;
/* * Set the access rights in AMR IAMR and UAMOR registers for @pkey to that * specified in @init_val.
*/ int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, unsignedlong init_val)
{
u64 new_amr_bits = 0x0ul;
u64 new_iamr_bits = 0x0ul;
u64 pkey_bits, uamor_pkey_bits;
/* * Check whether the key is disabled by UAMOR.
*/
pkey_bits = 0x3ul << pkeyshift(pkey);
uamor_pkey_bits = (default_uamor & pkey_bits);
/* * Both the bits in UAMOR corresponding to the key should be set
*/ if (uamor_pkey_bits != pkey_bits) return -EINVAL;
if (init_val & PKEY_DISABLE_EXECUTE) { if (!pkey_execute_disable_supported) return -EINVAL;
new_iamr_bits |= IAMR_EX_BIT;
}
init_iamr(pkey, new_iamr_bits);
/* Set the bits we need in AMR: */ if (init_val & PKEY_DISABLE_ACCESS)
new_amr_bits |= AMR_RD_BIT | AMR_WR_BIT; elseif (init_val & PKEY_DISABLE_WRITE)
new_amr_bits |= AMR_WR_BIT;
init_amr(pkey, new_amr_bits); return 0;
}
int execute_only_pkey(struct mm_struct *mm)
{ return mm->context.execute_only_pkey;
}
staticinlinebool vma_is_pkey_exec_only(struct vm_area_struct *vma)
{ /* Do this check first since the vm_flags should be hot */ if ((vma->vm_flags & VM_ACCESS_FLAGS) != VM_EXEC) returnfalse;
/* * This should only be called for *plain* mprotect calls.
*/ int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, int pkey)
{ /* * If the currently associated pkey is execute-only, but the requested * protection is not execute-only, move it back to the default pkey.
*/ if (vma_is_pkey_exec_only(vma) && (prot != PROT_EXEC)) return 0;
/* * The requested protection is execute-only. Hence let's use an * execute-only pkey.
*/ if (prot == PROT_EXEC) {
pkey = execute_only_pkey(vma->vm_mm); if (pkey > 0) return pkey;
}
/* Nothing to override. */ return vma_pkey(vma);
}
/* * We only want to enforce protection keys on the current thread because we * effectively have no access to AMR/IAMR for other threads or any way to tell * which AMR/IAMR in a threaded process we could use. * * So do not enforce things if the VMA is not from the current mm, or if we are * in a kernel thread.
*/ bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write, bool execute, bool foreign)
{ if (!mmu_has_feature(MMU_FTR_PKEY)) returntrue; /* * Do not enforce our key-permissions on a foreign vma.
*/ if (foreign || vma_is_foreign(vma)) returntrue;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.