[RFC v7 26/25] mm/mprotect, powerpc/mm/pkeys, x86/mm/pkeys: Add sysfs interface
Thiago Jung Bauermann
bauerman at linux.vnet.ibm.com
Sat Aug 12 03:34:43 AEST 2017
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_execute_supported <==
true
==> /sys/kernel/mm/protection_keys/total_keys <==
32
==> /sys/kernel/mm/protection_keys/usable_keys <==
30
And on an x86 without pkeys support:
$ head /sys/kernel/mm/protection_keys/*
==> /sys/kernel/mm/protection_keys/disable_execute_supported <==
false
==> /sys/kernel/mm/protection_keys/total_keys <==
1
==> /sys/kernel/mm/protection_keys/usable_keys <==
0
Signed-off-by: Thiago Jung Bauermann <bauerman at linux.vnet.ibm.com>
---
Ram asked me to add a sysfs interface for the memory protection keys
feature. Here it is.
If you have suggestions on what should be exposed, please let me know.
arch/powerpc/include/asm/pkeys.h | 2 ++
arch/powerpc/mm/pkeys.c | 12 ++++++++
arch/x86/include/asm/mmu_context.h | 34 +++++++++++-----------
arch/x86/include/asm/pkeys.h | 1 +
arch/x86/mm/pkeys.c | 5 ++++
mm/mprotect.c | 58 ++++++++++++++++++++++++++++++++++++++
6 files changed, 96 insertions(+), 16 deletions(-)
diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
index e61ed6c332db..bbc5a34cc6d6 100644
--- a/arch/powerpc/include/asm/pkeys.h
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -215,6 +215,8 @@ static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
return __arch_set_user_pkey_access(tsk, pkey, init_val);
}
+unsigned int arch_usable_pkeys(void);
+
static inline bool arch_pkeys_enabled(void)
{
return pkey_inited;
diff --git a/arch/powerpc/mm/pkeys.c b/arch/powerpc/mm/pkeys.c
index 1424c79f45f6..54efbb133049 100644
--- a/arch/powerpc/mm/pkeys.c
+++ b/arch/powerpc/mm/pkeys.c
@@ -272,3 +272,15 @@ 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;
+
+ reserved = hweight32(initial_allocation_mask);
+
+ return (pkeys_total > reserved) ? pkeys_total - reserved : 0;
+}
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index 68b329d77b3a..d2eabedd583a 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -105,13 +105,30 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
#endif
}
+#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
+#define PKEY_INITIAL_ALLOCATION_MAP 1
+
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+ unsigned long vma_pkey_mask = VM_PKEY_BIT0 | VM_PKEY_BIT1 |
+ VM_PKEY_BIT2 | VM_PKEY_BIT3;
+
+ return (vma->vm_flags & vma_pkey_mask) >> VM_PKEY_SHIFT;
+}
+#else
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+ return 0;
+}
+#endif
+
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;
}
@@ -205,21 +222,6 @@ static inline void arch_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
mpx_notify_unmap(mm, vma, start, end);
}
-#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
-static inline int vma_pkey(struct vm_area_struct *vma)
-{
- unsigned long vma_pkey_mask = VM_PKEY_BIT0 | VM_PKEY_BIT1 |
- VM_PKEY_BIT2 | VM_PKEY_BIT3;
-
- return (vma->vm_flags & vma_pkey_mask) >> VM_PKEY_SHIFT;
-}
-#else
-static inline int vma_pkey(struct vm_area_struct *vma)
-{
- return 0;
-}
-#endif
-
static inline bool __pkru_allows_pkey(u16 pkey, bool write)
{
u32 pkru = read_pkru();
diff --git a/arch/x86/include/asm/pkeys.h b/arch/x86/include/asm/pkeys.h
index fa8279972ddf..e1b25aa60530 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 2dab69a706ec..a3acca15ff83 100644
--- a/arch/x86/mm/pkeys.c
+++ b/arch/x86/mm/pkeys.c
@@ -123,6 +123,11 @@ int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, int pkey
return vma_pkey(vma);
}
+unsigned int arch_usable_pkeys(void)
+{
+ return arch_max_pkey() - hweight32(PKEY_INITIAL_ALLOCATION_MAP);
+}
+
#define PKRU_AD_KEY(pkey) (PKRU_AD_BIT << ((pkey) * PKRU_BITS_PER_PKEY))
/*
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 8edd0d576254..855744b9f7d6 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -554,4 +554,62 @@ SYSCALL_DEFINE1(pkey_free, int, pkey)
return ret;
}
+#ifdef CONFIG_SYSFS
+
+#define PKEYS_ATTR_RO(_name) \
+ static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
+
+static ssize_t total_keys_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", arch_max_pkey());
+}
+PKEYS_ATTR_RO(total_keys);
+
+static ssize_t usable_keys_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", arch_usable_pkeys());
+}
+PKEYS_ATTR_RO(usable_keys);
+
+static ssize_t disable_execute_supported_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+#ifdef PKEY_DISABLE_EXECUTE
+ if (arch_pkeys_enabled()) {
+ strcpy(buf, "true\n");
+ return sizeof("true\n") - 1;
+ }
+#endif
+
+ strcpy(buf, "false\n");
+ return sizeof("false\n") - 1;
+}
+PKEYS_ATTR_RO(disable_execute_supported);
+
+static struct attribute *pkeys_attrs[] = {
+ &total_keys_attr.attr,
+ &usable_keys_attr.attr,
+ &disable_execute_supported_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group pkeys_attr_group = {
+ .attrs = pkeys_attrs,
+ .name = "protection_keys",
+};
+
+static int __init pkeys_sysfs_init(void)
+{
+ int err;
+
+ err = sysfs_create_group(mm_kobj, &pkeys_attr_group);
+
+ return err;
+}
+late_initcall(pkeys_sysfs_init);
+#endif /* CONFIG_SYSFS */
+
#endif /* CONFIG_ARCH_HAS_PKEYS */
More information about the Linuxppc-dev
mailing list