Skip to contentSkip to conversation

mm, x86, powerpc: Memory Protection Keys enhancement

PATCH In review Ram Pai 2 participants 12 messages Sep 16, 2017 – Sep 22, 2017

Subsystems (9)
lore
Share & tools
lore

Ram Pai

author
#0 lore raw

cover mm, x86, powerpc: Memory Protection Keys enhancement

The patch-series enhances memory protection keys feature.

The patch(1) introduces an additional vma bit to support 32 pkeys. PowerPC supports 32 pkeys.

The patch(2,3) introduces a new interface arch_pkeys_enabled(),
this interface can be used by arch-neutral code to display
protection key value in smap.

The patch(4) introduces a syfs interface, to display the static attributes of the protection key. Eg: max number of keys.

The last two patches, (5,6) update documentation.

A separate patch series that enhances selftest will follow. The entire patch series that enables pkeys on powerpc is at
https://github.com/rampai/memorykeys.git memkey.v9-rc1

Testing:
-------
This patches are tested on powerpc platform using a enhaced set of selftests.
Could not test on x86 since I do not have access to one with pkey support.

History:
-------
version v3:
(1) sysfs interface - thanks Thiago.
(2) Documentation update.

version v2:
(1) Documentation is updated to better
capture the semantics.
(2) introduced arch_pkeys_enabled() to find
if an arch enables pkeys. Correspond- ing change in logic that displays key value in smaps.
(3) code rearranged in many places based on
comments from Dave Hansen, Balbir,
Anshuman.
version v1: Initial version

Ram Pai (5):
mm: introduce an additional vma bit for powerpc pkey
mm, x86 : introduce arch_pkeys_enabled()
mm: display pkey in smaps if arch_pkeys_enabled() is true Documentation/x86: Move protecton key documentation to arch neutral
directory
Documentation/vm: PowerPC specific updates to memory protection keys

Thiago Jung Bauermann (1):
mm/mprotect, powerpc/mm/pkeys, x86/mm/pkeys: Add sysfs interface

 Documentation/vm/protection-keys.txt  |  160 +++++++++++++++++++++++++++++++++
 Documentation/x86/protection-keys.txt |   85 -----------------
 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          |    2 +
 arch/x86/kernel/fpu/xstate.c          |    5 +
 arch/x86/kernel/setup.c               |    8 --
 arch/x86/mm/pkeys.c                   |    8 ++
 fs/proc/task_mmu.c                    |   17 ++--
 include/linux/mm.h                    |   16 ++--
 include/linux/pkeys.h                 |    9 ++
 mm/mprotect.c                         |   88 ++++++++++++++++++
 13 files changed, 317 insertions(+), 107 deletions(-)
 create mode 100644 Documentation/vm/protection-keys.txt
 delete mode 100644 Documentation/x86/protection-keys.txt
author
#1 lore raw

PATCH 1/6 mm: introduce an additional vma bit for powerpc pkey

Currently only 4bits are allocated in the vma flags to hold 16 keys. This is sufficient for x86. PowerPC supports 32 keys, which needs 5bits. This patch allocates an additional bit.

---
 fs/proc/task_mmu.c |    6 ++++--
 include/linux/mm.h |   16 ++++++++++------
 2 files changed, 14 insertions(+), 8 deletions(-)
fs/proc/task_mmu.c +4 -2
index b836fd6..cf25306 100644
@@ -661,13 +661,15 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
 		[ilog2(VM_MERGEABLE)]	= "mg",
 		[ilog2(VM_UFFD_MISSING)]= "um",
 		[ilog2(VM_UFFD_WP)]	= "uw",
-#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
+#ifdef CONFIG_ARCH_HAS_PKEYS
 		/* These come out via ProtectionKey: */
 		[ilog2(VM_PKEY_BIT0)]	= "",
 		[ilog2(VM_PKEY_BIT1)]	= "",
 		[ilog2(VM_PKEY_BIT2)]	= "",
 		[ilog2(VM_PKEY_BIT3)]	= "",
-#endif
+		/* Additional bit used by ppc64 */
+		[ilog2(VM_PKEY_BIT4)]	= "",
+#endif /* CONFIG_ARCH_HAS_PKEYS */
 	};
 	size_t i;
 
include/linux/mm.h +10 -6
index 46b9ac5..6d72ec0 100644
@@ -208,21 +208,25 @@ extern int overcommit_kbytes_handler(struct ctl_table *, int, void __user *,
 #define VM_HIGH_ARCH_BIT_1	33	/* bit only usable on 64-bit architectures */
 #define VM_HIGH_ARCH_BIT_2	34	/* bit only usable on 64-bit architectures */
 #define VM_HIGH_ARCH_BIT_3	35	/* bit only usable on 64-bit architectures */
+#define VM_HIGH_ARCH_BIT_4	36	/* bit only usable on 64-bit architectures */
 #define VM_HIGH_ARCH_0	BIT(VM_HIGH_ARCH_BIT_0)
 #define VM_HIGH_ARCH_1	BIT(VM_HIGH_ARCH_BIT_1)
 #define VM_HIGH_ARCH_2	BIT(VM_HIGH_ARCH_BIT_2)
 #define VM_HIGH_ARCH_3	BIT(VM_HIGH_ARCH_BIT_3)
+#define VM_HIGH_ARCH_4	BIT(VM_HIGH_ARCH_BIT_4)
 #endif /* CONFIG_ARCH_USES_HIGH_VMA_FLAGS */
 
-#if defined(CONFIG_X86)
-# define VM_PAT		VM_ARCH_1	/* PAT reserves whole VMA at once (x86) */
-#if defined (CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS)
+#ifdef CONFIG_ARCH_HAS_PKEYS
 # define VM_PKEY_SHIFT	VM_HIGH_ARCH_BIT_0
-# define VM_PKEY_BIT0	VM_HIGH_ARCH_0	/* A protection key is a 4-bit value */
-# define VM_PKEY_BIT1	VM_HIGH_ARCH_1
+# define VM_PKEY_BIT0	VM_HIGH_ARCH_0 /* A protection key is a 4-bit value */
+# define VM_PKEY_BIT1	VM_HIGH_ARCH_1 /* on x86 and 5-bit value on ppc64   */
 # define VM_PKEY_BIT2	VM_HIGH_ARCH_2
 # define VM_PKEY_BIT3	VM_HIGH_ARCH_3
-#endif
+# define VM_PKEY_BIT4	VM_HIGH_ARCH_4
+#endif /* CONFIG_ARCH_HAS_PKEYS */
+
+#if defined(CONFIG_X86)
+# define VM_PAT		VM_ARCH_1	/* PAT reserves whole VMA at once (x86) */
 #elif defined(CONFIG_PPC)
 # define VM_SAO		VM_ARCH_1	/* Strong Access Ordering (powerpc) */
 #elif defined(CONFIG_PARISC)
Signature · 7 lines
1.7.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Acked-by on v1 1/6
#2 lore raw

Re: [PATCH 1/6] mm: introduce an additional vma bit for powerpc pkey

Quoted 6 lines · On Fri, 15 Sep 2017 18:21:05 -0700 Ram Pai <[email protected]> wrote:

Currently only 4bits are allocated in the vma flags to hold 16 keys. This is sufficient for x86. PowerPC supports 32 keys, which needs 5bits. This patch allocates an additional bit.

---

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

author
#3 lore raw

PATCH 2/6 mm, x86 : introduce arch_pkeys_enabled()

In reply to Ram Pai

Arch neutral code needs to know if the architecture supports protection keys to display protection key in smaps. Hence introducing arch_pkeys_enabled().

This patch also provides x86 implementation for
arch_pkeys_enabled().

---
 arch/x86/include/asm/pkeys.h |    1 +
 arch/x86/kernel/fpu/xstate.c |    5 +++++
 include/linux/pkeys.h        |    5 +++++
 3 files changed, 11 insertions(+), 0 deletions(-)
arch/x86/include/asm/pkeys.h +1 -0
index b3b09b9..fa82799 100644
@@ -5,6 +5,7 @@
 
 extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 		unsigned long init_val);
+extern bool arch_pkeys_enabled(void);
 
 /*
  * Try to dedicate one of the protection keys to be used as an
arch/x86/kernel/fpu/xstate.c +5 -0
index c24ac1e..df594b8 100644
@@ -918,6 +918,11 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 
 	return 0;
 }
+
+bool arch_pkeys_enabled(void)
+{
+	return boot_cpu_has(X86_FEATURE_OSPKE);
+}
 #endif /* ! CONFIG_ARCH_HAS_PKEYS */
 
 /*
include/linux/pkeys.h +5 -0
index a1bacf1..d120810 100644
@@ -34,6 +34,11 @@ static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 	return 0;
 }
 
+static inline bool arch_pkeys_enabled(void)
+{
+	return false;
+}
+
 static inline void copy_init_pkru_to_fpregs(void)
 {
 }
Signature · 7 lines
1.7.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
author
#4 lore raw

PATCH 3/6 mm: display pkey in smaps if arch_pkeys_enabled() is true

In reply to Ram Pai

Currently the architecture specific code is expected to display the protection keys in smap for a given vma. This can lead to redundant code and possibly to divergent formats in which the key gets displayed.

This patch changes the implementation. It displays the pkey only if the architecture support pkeys.

x86 arch_show_smap() function is not needed anymore. Delete it.

---
 arch/x86/kernel/setup.c |    8 --------
 fs/proc/task_mmu.c      |   11 ++++++-----
 2 files changed, 6 insertions(+), 13 deletions(-)
arch/x86/kernel/setup.c +0 -8
index 3486d04..1953bce 100644
@@ -1340,11 +1340,3 @@ static int __init register_kernel_offset_dumper(void)
 	return 0;
 }
 __initcall(register_kernel_offset_dumper);
-
-void arch_show_smap(struct seq_file *m, struct vm_area_struct *vma)
-{
-	if (!boot_cpu_has(X86_FEATURE_OSPKE))
-		return;
-
-	seq_printf(m, "ProtectionKey:  %8u\n", vma_pkey(vma));
-}
fs/proc/task_mmu.c +6 -5
index cf25306..667d44a 100644
@@ -16,6 +16,7 @@
 #include <linux/mmu_notifier.h>
 #include <linux/page_idle.h>
 #include <linux/shmem_fs.h>
+#include <linux/pkeys.h>
 
 #include <asm/elf.h>
 #include <linux/uaccess.h>
@@ -714,10 +715,6 @@ static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask,
 }
 #endif /* HUGETLB_PAGE */
 
-void __weak arch_show_smap(struct seq_file *m, struct vm_area_struct *vma)
-{
-}
-
 static int show_smap(struct seq_file *m, void *v, int is_pid)
 {
 	struct vm_area_struct *vma = v;
@@ -803,7 +800,11 @@ static int show_smap(struct seq_file *m, void *v, int is_pid)
 		   (vma->vm_flags & VM_LOCKED) ?
 			(unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0);
 
-	arch_show_smap(m, vma);
+#ifdef CONFIG_ARCH_HAS_PKEYS
+	if (arch_pkeys_enabled())
+		seq_printf(m, "ProtectionKey:  %8u\n", vma_pkey(vma));
+#endif
+
 	show_smap_vma_flags(m, vma);
 	m_cache_vma(m, vma);
 	return 0;
Signature · 7 lines
1.7.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#5 lore raw

Re: [PATCH 3/6] mm: display pkey in smaps if arch_pkeys_enabled() is true

Quoted 57 lines · On Fri, 15 Sep 2017 18:21:07 -0700 Ram Pai <[email protected]> wrote:

Currently the architecture specific code is expected to display the protection keys in smap for a given vma. This can lead to redundant code and possibly to divergent formats in which the key gets displayed.

This patch changes the implementation. It displays the pkey only if the architecture support pkeys.

x86 arch_show_smap() function is not needed anymore. Delete it.

---
 arch/x86/kernel/setup.c |    8 --------
 fs/proc/task_mmu.c      |   11 ++++++-----
 2 files changed, 6 insertions(+), 13 deletions(-)
arch/x86/kernel/setup.c +0 -8
index 3486d04..1953bce 100644
@@ -1340,11 +1340,3 @@ static int __init register_kernel_offset_dumper(void)
 	return 0;
 }
 __initcall(register_kernel_offset_dumper);
-
-void arch_show_smap(struct seq_file *m, struct vm_area_struct *vma)
-{
-	if (!boot_cpu_has(X86_FEATURE_OSPKE))
-		return;
-
-	seq_printf(m, "ProtectionKey:  %8u\n", vma_pkey(vma));
-}
fs/proc/task_mmu.c +1 -4
index cf25306..667d44a 100644
@@ -16,6 +16,7 @@
 #include <linux/mmu_notifier.h>
 #include <linux/page_idle.h>
 #include <linux/shmem_fs.h>
+#include <linux/pkeys.h>
 
 #include <asm/elf.h>
 #include <linux/uaccess.h>
@@ -714,10 +715,6 @@ static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask,
 }
 #endif /* HUGETLB_PAGE */
 
-void __weak arch_show_smap(struct seq_file *m, struct vm_area_struct *vma)
-{
-}
-
 static int show_smap(struct seq_file *m, void *v, int is_pid)
 {
 	struct vm_area_struct *vma = v;

fs/proc/task_mmu.c static int show_smap(struct seq_file *m, void *v, int is_pid) · line 806

Quoted 8 lines
fs/proc/task_mmu.c +4 -1
@@ -803,7 +800,11 @@ static int show_smap(struct seq_file *m, void *v, int is_pid)
 		   (vma->vm_flags & VM_LOCKED) ?
 			(unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0);
 
-	arch_show_smap(m, vma);
+#ifdef CONFIG_ARCH_HAS_PKEYS
+	if (arch_pkeys_enabled())
+		seq_printf(m, "ProtectionKey:  %8u\n", vma_pkey(vma));
+#endif

Can CONFIG_ARCH_HAS_PKEYS be true, but the kernel compiled without support for them or it's just not enabled? I think the earlier per_arch function was better

Balbir

#6 lore raw

Re: [PATCH 3/6] mm: display pkey in smaps if arch_pkeys_enabled() is true

In reply to Ram Pai

fs/proc/task_mmu.c static int show_smap(struct seq_file *m, void *v, int is_pid) · line 804

Quoted 2 lines · On Fri, 15 Sep 2017 18:21:07 -0700 Ram Pai <[email protected]> wrote:
fs/proc/task_mmu.c +2 -0
+#ifdef CONFIG_ARCH_HAS_PKEYS
+	if (arch_pkeys_enabled())

Sorry, I missed this bit in my previous review
the patch makes sense

fs/proc/task_mmu.c static int show_smap(struct seq_file *m, void *v, int is_pid) · line 807

Quoted 3 lines
fs/proc/task_mmu.c +3 -0
+		seq_printf(m, "ProtectionKey:  %8u\n", vma_pkey(vma));
+#endif
+

Balbir

author
#7 lore raw

PATCH 4/6 mm/mprotect, powerpc/mm/pkeys, x86/mm/pkeys: Add sysfs interface

In reply to Ram Pai

From: Thiago Jung Bauermann <[email protected]>

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

---
 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(-)
arch/powerpc/include/asm/pkeys.h +2 -0
index baac435..5924325 100644
@@ -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);
arch/powerpc/mm/pkeys.c +20 -0
index 07e76dc..33c9207 100644
@@ -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));
+}
arch/x86/include/asm/mmu_context.h +3 -1
index 265c907..e960ab2 100644
@@ -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_MAP	1
+
 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;
 	}
arch/x86/include/asm/pkeys.h +1 -0
index fa82799..e1b25aa 100644
@@ -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 */
arch/x86/mm/pkeys.c +8 -0
index 2dab69a..6b7f4e1 100644
@@ -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)	(PKRU_AD_BIT << ((pkey) * PKRU_BITS_PER_PKEY))
 
 /*
include/linux/pkeys.h +4 -0
index d120810..9350d44 100644
@@ -43,6 +43,10 @@ static inline void copy_init_pkru_to_fpregs(void)
 {
 }
 
+unsigned int arch_usable_pkeys(void)
+{
+	return 0;
+}
 #endif /* ! CONFIG_ARCH_HAS_PKEYS */
 
 #endif /* _LINUX_PKEYS_H */
mm/mprotect.c +88 -0

92 lines not on this page · raw message

Signature · 7 lines
1.7.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#8 lore raw

Re: [PATCH 4/6] mm/mprotect, powerpc/mm/pkeys, x86/mm/pkeys: Add sysfs interface

Quoted 38 lines · On Fri, 15 Sep 2017 18:21:08 -0700 Ram Pai <[email protected]> wrote:

From: Thiago Jung Bauermann <[email protected]>

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

Quoted 6 lines

==> /sys/kernel/mm/protection_keys/usable_keys <== 0

---

Just curious, how do you see this being used? For debugging or will applications parse these properties and use them? It's hard for an application to partition its address space among keys at runtime, would you agree?

Balbir Singh.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

author
#9 lore raw

Re: [PATCH 4/6] mm/mprotect, powerpc/mm/pkeys, x86/mm/pkeys: Add sysfs interface

Quoted 44 lines · Balbir Singh
Quoted 41 lines · On Fri, 15 Sep 2017 18:21:08 -0700 Ram Pai <[email protected]> wrote:

From: Thiago Jung Bauermann <[email protected]>

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

Quoted 6 lines
Quoted 3 lines

---

Just curious, how do you see this being used?
For debugging or will applications parse these properties and use them?

Its upto the application to determine the best way to fully exploit all the keys. But that cannot happen if the application has no easy way to determine the number of available keys.

Quoted 2 lines

It's hard for an application to partition its address space among keys at runtime, would you agree?

Why would it be hard? Because the application may not know; in advance, the range of its address space? Well that is true. But that may not be the best strategy. It should not be based on how large its address space range is, rather it should be based on how many unique access-domains it will need. It can associate a key with each domain and it can associate address-ranges to the appropriate domains. The more the number of keys the more the number of access-domains and finer the control.

Quoted 2 lines

Balbir Singh.

Signature · 7 lines
Ram Pai

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
author
#10 lore raw

PATCH 5/6 Documentation/x86: Move protecton key documentation to arch neutral directory

In reply to Ram Pai

Since PowerPC and Intel both support memory protection keys, moving the documenation to arch-neutral directory.

---
 Documentation/vm/protection-keys.txt  |   85 +++++++++++++++++++++++++++++++++
 Documentation/x86/protection-keys.txt |   85 ---------------------------------
 2 files changed, 85 insertions(+), 85 deletions(-)
 create mode 100644 Documentation/vm/protection-keys.txt
 delete mode 100644 Documentation/x86/protection-keys.txt
Documentation/vm/protection-keys.txt new file +85 -0
new file mode 100644
index 0000000..b643045
@@ -0,0 +1,85 @@
+Memory Protection Keys for Userspace (PKU aka PKEYs) is a CPU feature
+which will be found on future Intel CPUs.
+
+Memory Protection Keys provides a mechanism for enforcing page-based
+protections, but without requiring modification of the page tables
+when an application changes protection domains.  It works by
+dedicating 4 previously ignored bits in each page table entry to a
+"protection key", giving 16 possible keys.
+
+There is also a new user-accessible register (PKRU) with two separate
+bits (Access Disable and Write Disable) for each key.  Being a CPU
+register, PKRU is inherently thread-local, potentially giving each
+thread a different set of protections from every other thread.
+
+There are two new instructions (RDPKRU/WRPKRU) for reading and writing
+to the new register.  The feature is only available in 64-bit mode,
+even though there is theoretically space in the PAE PTEs.  These
+permissions are enforced on data access only and have no effect on
+instruction fetches.
+
+=========================== Syscalls ===========================
+
+There are 3 system calls which directly interact with pkeys:
+
+	int pkey_alloc(unsigned long flags, unsigned long init_access_rights)
+	int pkey_free(int pkey);
+	int pkey_mprotect(unsigned long start, size_t len,
+			  unsigned long prot, int pkey);
+
+Before a pkey can be used, it must first be allocated with
+pkey_alloc().  An application calls the WRPKRU instruction
+directly in order to change access permissions to memory covered
+with a key.  In this example WRPKRU is wrapped by a C function
+called pkey_set().
+
+	int real_prot = PROT_READ|PROT_WRITE;
+	pkey = pkey_alloc(0, PKEY_DENY_WRITE);
+	ptr = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+	ret = pkey_mprotect(ptr, PAGE_SIZE, real_prot, pkey);
+	... application runs here
+
+Now, if the application needs to update the data at 'ptr', it can
+gain access, do the update, then remove its write access:
+
+	pkey_set(pkey, 0); // clear PKEY_DENY_WRITE
+	*ptr = foo; // assign something
+	pkey_set(pkey, PKEY_DENY_WRITE); // set PKEY_DENY_WRITE again
+
+Now when it frees the memory, it will also free the pkey since it
+is no longer in use:
+
+	munmap(ptr, PAGE_SIZE);
+	pkey_free(pkey);
+
+(Note: pkey_set() is a wrapper for the RDPKRU and WRPKRU instructions.
+ An example implementation can be found in
+ tools/testing/selftests/x86/protection_keys.c)
+
+=========================== Behavior ===========================
+
+The kernel attempts to make protection keys consistent with the
+behavior of a plain mprotect().  For instance if you do this:
+
+	mprotect(ptr, size, PROT_NONE);
+	something(ptr);
+
+you can expect the same effects with protection keys when doing this:
+
+	pkey = pkey_alloc(0, PKEY_DISABLE_WRITE | PKEY_DISABLE_READ);
+	pkey_mprotect(ptr, size, PROT_READ|PROT_WRITE, pkey);
+	something(ptr);
+
+That should be true whether something() is a direct access to 'ptr'
+like:
+
+	*ptr = foo;
+
+or when the kernel does the access on the application's behalf like
+with a read():
+
+	read(fd, ptr, 1);
+
+The kernel will send a SIGSEGV in both cases, but si_code will be set
+to SEGV_PKERR when violating protection keys versus SEGV_ACCERR when
+the plain mprotect() permissions are violated.
Documentation/x86/protection-keys.txt deleted +0 -85

85 lines not on this page · raw message

Signature · 1 line
1.7.1
author
#11 lore raw

PATCH 6/6 Documentation/vm: PowerPC specific updates to memory protection keys

In reply to Ram Pai

Add documentation updates that capture PowerPC specific changes.

---
 Documentation/vm/protection-keys.txt |  125 +++++++++++++++++++++++++++-------
 1 files changed, 100 insertions(+), 25 deletions(-)
Documentation/vm/protection-keys.txt +100 -25
index b643045..ef5f73b 100644
@@ -1,22 +1,45 @@
-Memory Protection Keys for Userspace (PKU aka PKEYs) is a CPU feature
-which will be found on future Intel CPUs.
-
-Memory Protection Keys provides a mechanism for enforcing page-based
-protections, but without requiring modification of the page tables
-when an application changes protection domains.  It works by
-dedicating 4 previously ignored bits in each page table entry to a
-"protection key", giving 16 possible keys.
-
-There is also a new user-accessible register (PKRU) with two separate
-bits (Access Disable and Write Disable) for each key.  Being a CPU
-register, PKRU is inherently thread-local, potentially giving each
-thread a different set of protections from every other thread.
-
-There are two new instructions (RDPKRU/WRPKRU) for reading and writing
-to the new register.  The feature is only available in 64-bit mode,
-even though there is theoretically space in the PAE PTEs.  These
-permissions are enforced on data access only and have no effect on
-instruction fetches.
+Memory Protection Keys for Userspace (PKU aka PKEYs) is a CPU feature found on
+future Intel CPUs and on PowerPC 5 and higher CPUs.
+
+Memory Protection Keys provide a mechanism for enforcing page-based
+protections, but without requiring modification of the page tables when an
+application changes protection domains.
+
+It works by dedicating bits in each page table entry to a "protection key".
+There is also a user-accessible register with two separate bits for each
+key.  Being a CPU register, the user-accessible register is inherently
+thread-local, potentially giving each thread a different set of protections
+from every other thread.
+
+On Intel:
+
+	Four previously bits are used the page table entry giving 16 possible keys.
+
+	The user accessible register(PKRU) has a bit each per key to disable
+	access and to disable write.
+
+	The feature is only available in 64-bit mode, even though there is
+	theoretically space in the PAE PTEs.  These permissions are enforced on
+	data access only and have no effect on instruction fetches.
+
+On PowerPC:
+
+	Five bits in the page table entry are used giving 32 possible keys.
+	This support is currently for Hash Page Table mode only.
+
+	The user accessible register(AMR) has a bit each per key to disable
+	read and write. Access disable can be achieved by disabling
+	read and write.
+
+	'mtspr 0xd, mem' reads the AMR register
+	'mfspr mem, 0xd' writes into the AMR register.
+
+	Execution can  be  disabled by allocating a key with execute-disabled
+	permission. The execute-permissions on the key; however, cannot be
+	changed through a user accessible register. The CPU will not allow
+	execution of instruction in pages that are associated with
+	execute-disabled key.
+
 
 =========================== Syscalls ===========================
 
@@ -28,9 +51,9 @@ There are 3 system calls which directly interact with pkeys:
 			  unsigned long prot, int pkey);
 
 Before a pkey can be used, it must first be allocated with
-pkey_alloc().  An application calls the WRPKRU instruction
+pkey_alloc().  An application calls the WRPKRU/AMR instruction
 directly in order to change access permissions to memory covered
-with a key.  In this example WRPKRU is wrapped by a C function
+with a key.  In this example WRPKRU/AMR is wrapped by a C function
 called pkey_set().
 
 	int real_prot = PROT_READ|PROT_WRITE;
@@ -52,11 +75,11 @@ is no longer in use:
 	munmap(ptr, PAGE_SIZE);
 	pkey_free(pkey);
 
-(Note: pkey_set() is a wrapper for the RDPKRU and WRPKRU instructions.
+(Note: pkey_set() is a wrapper for the RDPKRU,WRPKRU or AMR instructions.
  An example implementation can be found in
- tools/testing/selftests/x86/protection_keys.c)
+ tools/testing/selftests/vm/protection_keys.c)
 
-=========================== Behavior ===========================
+=========================== Behavior =================================
 
 The kernel attempts to make protection keys consistent with the
 behavior of a plain mprotect().  For instance if you do this:
@@ -66,7 +89,7 @@ behavior of a plain mprotect().  For instance if you do this:
 
 you can expect the same effects with protection keys when doing this:
 
-	pkey = pkey_alloc(0, PKEY_DISABLE_WRITE | PKEY_DISABLE_READ);
+	pkey = pkey_alloc(0, PKEY_DISABLE_ACCESS);
 	pkey_mprotect(ptr, size, PROT_READ|PROT_WRITE, pkey);
 	something(ptr);
 
@@ -83,3 +106,55 @@ with a read():
 The kernel will send a SIGSEGV in both cases, but si_code will be set
 to SEGV_PKERR when violating protection keys versus SEGV_ACCERR when
 the plain mprotect() permissions are violated.
+
+========================== sysfs Interface ==========================
+
+Information about support of protection keys on the system can be
+found in the /sys/kernel/mm/protection_keys directory, which
+contains the following files:
+
+- total_keys: Shows the number of keys supported by the hardware.
+    Not all of those keys may be available for use by a process
+    because the platform or operating system may reserve some keys
+    for their own use.
+
+- usable_keys: Shows the minimum number of keys guaranteed to be
+    available for use by a process. In other words: total_keys minus
+    the keys reserved by the platform or operating system. This
+    number doesn't change to reflect keys that are already being
+    used by the process reading the file.
+
+    There may be one more key available than what is advertised in
+    this file because the kernel may use one key for mprotect()
+    calls setting up memory with execute-only permissions. This file
+    assumes that this key is being used, but if it is not the
+    process will have one more key it can use for other purposes.
+
+- disable_access_supported: Tells whether the system supports keys
+    which disallow reading from a given page (i.e., the
+    PKEY_DISABLE_ACCESS flag is supported).
+
+- disable_write_supported: Tells whether the system supports keys
+    which disallow writing to a given page (i.e., the
+    PKEY_DISABLE_WRITE flag is supported).
+
+- disable_execute_supported: Tells whether the system supports keys
+    which disallow code execution from a given page (i.e., the
+    PKEY_DISABLE_EXECUTE flag is supported).
+
+====================================================================
+		Semantic differences
+
+The following semantic differences exist between x86 and power.
+
+a) powerpc (PowerPC8 onwards) *also* allows creation of a key with
+   execute-disabled.
+	The following is allowed
+	pkey = pkey_alloc(0, PKEY_DISABLE_EXECUTE);
+
+b) changes to the key permission bits from a signal handler do not
+   persist on x86. The PKRU specific  fpregs  entry  need   to  be
+   modified for it to persist.  On powerpc the key  permission can
+   be  modified  by  programming  the AMR register from the signal
+   handler. The changes persist across signal boundaries.
+=====================================================================
Signature · 7 lines
1.7.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>