From: Thiago Jung Bauermann
Expose useful information for programs using memory protection keys.
Provide implementation for powerpc and x86.
On a powerpc system with pkeys support, here is what is shown:
$ head /sys/kernel/mm/protection_keys/*
==> /sys/kernel/mm/protection_keys/disable_access_supported <==
true
==> /sys/kernel/mm/protection_keys/disable_execute_supported <==
true
==> /sys/kernel/mm/protection_keys/disable_write_supported <==
true
==> /sys/kernel/mm/protection_keys/total_keys <==
32
==> /sys/kernel/mm/protection_keys/usable_keys <==
29
And on an x86 without pkeys support:
$ head /sys/kernel/mm/protection_keys/*
==> /sys/kernel/mm/protection_keys/disable_access_supported <==
false
==> /sys/kernel/mm/protection_keys/disable_execute_supported <==
false
==> /sys/kernel/mm/protection_keys/disable_write_supported <==
false
==> /sys/kernel/mm/protection_keys/total_keys <==
1
==> /sys/kernel/mm/protection_keys/usable_keys <==
0
Signed-off-by: Ram Pai
Signed-off-by: Thiago Jung Bauermann
---
arch/powerpc/include/asm/pkeys.h |2 +
arch/powerpc/mm/pkeys.c| 20
arch/x86/include/asm/mmu_context.h |4 +-
arch/x86/include/asm/pkeys.h |1 +
arch/x86/mm/pkeys.c|8 +++
include/linux/pkeys.h |4 ++
mm/mprotect.c | 88
7 files changed, 126 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
index baac435..5924325 100644
--- a/arch/powerpc/include/asm/pkeys.h
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -244,6 +244,8 @@ static inline bool pkey_mmu_enabled(void)
return cpu_has_feature(CPU_FTR_PKEY);
}
+extern bool arch_supports_pkeys(int cap);
+extern unsigned int arch_usable_pkeys(void);
extern void thread_pkey_regs_save(struct thread_struct *thread);
extern void thread_pkey_regs_restore(struct thread_struct *new_thread,
struct thread_struct *old_thread);
diff --git a/arch/powerpc/mm/pkeys.c b/arch/powerpc/mm/pkeys.c
index 07e76dc..33c9207 100644
--- a/arch/powerpc/mm/pkeys.c
+++ b/arch/powerpc/mm/pkeys.c
@@ -373,3 +373,23 @@ bool arch_vma_access_permitted(struct vm_area_struct *vma,
return pkey_access_permitted(pkey, write, execute);
}
+
+unsigned int arch_usable_pkeys(void)
+{
+ unsigned int reserved;
+
+ if (!pkey_inited)
+ return 0;
+
+ /* Reserve one more to account for the execute-only pkey. */
+ reserved = hweight32(initial_allocation_mask) + 1;
+
+ return pkeys_total > reserved ? pkeys_total - reserved : 0;
+}
+
+bool arch_supports_pkeys(int cap)
+{
+ if (cap & PKEY_DISABLE_EXECUTE)
+ return pkey_execute_disable_support;
+ return (cap & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));
+}
diff --git a/arch/x86/include/asm/mmu_context.h
b/arch/x86/include/asm/mmu_context.h
index 265c907..e960ab2 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -129,13 +129,15 @@ static inline void enter_lazy_tlb(struct mm_struct *mm,
struct task_struct *tsk)
this_cpu_write(cpu_tlbstate.state, TLBSTATE_LAZY);
}
+#define PKEY_INITIAL_ALLOCATION_MAP1
+
static inline int init_new_context(struct task_struct *tsk,
struct mm_struct *mm)
{
#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
if (cpu_feature_enabled(X86_FEATURE_OSPKE)) {
/* pkey 0 is the default and always allocated */
- mm->context.pkey_allocation_map = 0x1;
+ mm->context.pkey_allocation_map = PKEY_INITIAL_ALLOCATION_MAP;
/* -1 means unallocated or invalid */
mm->context.execute_only_pkey = -1;
}
diff --git a/arch/x86/include/asm/pkeys.h b/arch/x86/include/asm/pkeys.h
index fa82799..e1b25aa 100644
--- a/arch/x86/include/asm/pkeys.h
+++ b/arch/x86/include/asm/pkeys.h
@@ -105,5 +105,6 @@ extern int arch_set_user_pkey_access(struct task_struct
*tsk, int pkey,
extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
unsigned long init_val);
extern void copy_init_pkru_to_fpregs(void);
+extern unsigned int arch_usable_pkeys(void);
#endif /*_ASM_X86_PKEYS_H */
diff --git a/arch/x86/mm/pkeys.c b/arch/x86/mm/pkeys.c
index 2dab69a..6b7f4e1 100644
--- a/arch/x86/mm/pkeys.c
+++ b/arch/x86/mm/pkeys.c
@@ -123,6 +123,14 @@ int __arch_override_mprotect_pkey(struct vm_area_struct
*vma, int prot, int pkey
return vma_pkey(vma);
}
+unsigned int arch_usable_pkeys(void)
+{
+ /* Reserve one more to account for the execute-only pkey. */
+ unsigned int reserved = hweight32(PKEY_INITIAL_ALLOCATION_MAP) + 1;
+
+ return arch_max_pkey() > reserved ? arch_max_pkey() - reserved : 0;
+}
+
#define PKRU_AD_KEY(pkey)