Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1675513 > unrolled thread
| Started by | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| First post | 2017-06-27 12:20 +0200 |
| Last post | 2017-06-27 12:50 +0200 |
| Articles | 11 — 3 participants |
Back to article view | Back to linux.kernel
[RFC v4 00/17] powerpc: Memory Protection Keys Ram Pai <linuxram@us.ibm.com> - 2017-06-27 12:20 +0200
[RFC v4 09/17] powerpc: call the hash functions with the correct pkey value Ram Pai <linuxram@us.ibm.com> - 2017-06-27 12:20 +0200
Re: [RFC v4 09/17] powerpc: call the hash functions with the correct pkey value "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> - 2017-06-27 17:30 +0200
Re: [RFC v4 09/17] powerpc: call the hash functions with the correct pkey value Ram Pai <linuxram@us.ibm.com> - 2017-06-28 09:20 +0200
[RFC v4 02/17] mm: ability to disable execute permission on a key at creation Ram Pai <linuxram@us.ibm.com> - 2017-06-27 12:20 +0200
Re: [RFC v4 02/17] mm: ability to disable execute permission on a key at creation Balbir Singh <bsingharora@gmail.com> - 2017-06-27 13:40 +0200
[RFC v4 15/17] Documentation: Move protecton key documentation to arch neutral directory Ram Pai <linuxram@us.ibm.com> - 2017-06-27 12:20 +0200
[RFC v4 03/17] x86: key creation with PKEY_DISABLE_EXECUTE disallowed Ram Pai <linuxram@us.ibm.com> - 2017-06-27 12:20 +0200
Re: [RFC v4 03/17] x86: key creation with PKEY_DISABLE_EXECUTE disallowed Balbir Singh <bsingharora@gmail.com> - 2017-06-27 13:40 +0200
[RFC v4 04/17] powerpc: Implement sys_pkey_alloc and sys_pkey_free system call Ram Pai <linuxram@us.ibm.com> - 2017-06-27 12:20 +0200
Re: [RFC v4 00/17] powerpc: Memory Protection Keys Balbir Singh <bsingharora@gmail.com> - 2017-06-27 12:50 +0200
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-06-27 12:20 +0200 |
| Subject | [RFC v4 00/17] powerpc: Memory Protection Keys |
| Message-ID | <tWVLc-7w2-3@gated-at.bofh.it> |
Memory protection keys enable applications to protect its
address space from inadvertent access or corruption from
itself.
The overall idea:
A process allocates a key and associates it with
a address range within its address space.
The process than can dynamically set read/write
permissions on the key without involving the
kernel. Any code that violates the permissions
off the address space; as defined by its associated
key, will receive a segmentation fault.
This patch series enables the feature on PPC64 HPTE
platform.
ISA3.0 section 5.7.13 describes the detailed specifications.
Testing:
This patch series has passed all the protection key
tests available in the selftests directory.
The tests are updated to work on both x86 and powerpc.
version v4:
(1) patches no more depend on the pte bits to program
the hpte -- comment by Balbir
(2) documentation updates
(3) fixed a bug in the selftest.
(4) unlike x86, powerpc lets signal handler change key
permission bits; the change will persist across
signal handler boundaries. Earlier we allowed
the signal handler to modify a field in the siginfo
structure which would than be used by the kernel
to program the key protection register (AMR)
-- resolves a issue raised by Ben.
"Calls to sys_swapcontext with a made-up context
will end up with a crap AMR if done by code who
didn't know about that register".
(5) these changes enable protection keys on 4k-page
kernel aswell.
version v3:
(1) split the patches into smaller consumable
patches.
(2) added the ability to disable execute permission
on a key at creation.
(3) rename calc_pte_to_hpte_pkey_bits() to
pte_to_hpte_pkey_bits() -- suggested by Anshuman
(4) some code optimization and clarity in
do_page_fault()
(5) A bug fix while invalidating a hpte slot in
__hash_page_4K() -- noticed by Aneesh
version v2:
(1) documentation and selftest added
(2) fixed a bug in 4k hpte backed 64k pte where page
invalidation was not done correctly, and
initialization of second-part-of-the-pte was not
done correctly if the pte was not yet Hashed
with a hpte. Reported by Aneesh.
(3) Fixed ABI breakage caused in siginfo structure.
Reported by Anshuman.
version v1: Initial version
Ram Pai (17):
mm: introduce an additional vma bit for powerpc pkey
mm: ability to disable execute permission on a key at creation
x86: key creation with PKEY_DISABLE_EXECUTE disallowed
powerpc: Implement sys_pkey_alloc and sys_pkey_free system call
powerpc: store and restore the pkey state across context switches
powerpc: Implementation for sys_mprotect_pkey() system call
powerpc: make the hash functions protection-key aware
powerpc: Program HPTE key protection bits
powerpc: call the hash functions with the correct pkey value
powerpc: Macro the mask used for checking DSI exception
powerpc: Handle exceptions caused by pkey violation
powerpc: Deliver SEGV signal on pkey violation
selftest: Move protecton key selftest to arch neutral directory
selftest: PowerPC specific test updates to memory protection keys
Documentation: Move protecton key documentation to arch neutral
directory
Documentation: PowerPC specific updates to memory protection keys
procfs: display the protection-key number associated with a vma
Documentation/filesystems/proc.txt | 3 +-
Documentation/vm/protection-keys.txt | 134 +++
Documentation/x86/protection-keys.txt | 85 --
Makefile | 2 +-
arch/powerpc/Kconfig | 15 +
arch/powerpc/include/asm/book3s/64/hash.h | 2 +-
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 19 +-
arch/powerpc/include/asm/book3s/64/mmu.h | 10 +
arch/powerpc/include/asm/book3s/64/pgtable.h | 62 ++
arch/powerpc/include/asm/mman.h | 8 +-
arch/powerpc/include/asm/mmu_context.h | 12 +
arch/powerpc/include/asm/paca.h | 1 +
arch/powerpc/include/asm/pkeys.h | 159 +++
arch/powerpc/include/asm/processor.h | 5 +
arch/powerpc/include/asm/reg.h | 7 +-
arch/powerpc/include/asm/systbl.h | 3 +
arch/powerpc/include/asm/unistd.h | 6 +-
arch/powerpc/include/uapi/asm/ptrace.h | 3 +-
arch/powerpc/include/uapi/asm/unistd.h | 3 +
arch/powerpc/kernel/asm-offsets.c | 5 +
arch/powerpc/kernel/exceptions-64s.S | 18 +-
arch/powerpc/kernel/process.c | 18 +
arch/powerpc/kernel/signal_32.c | 5 +
arch/powerpc/kernel/signal_64.c | 4 +
arch/powerpc/kernel/traps.c | 49 +
arch/powerpc/mm/Makefile | 1 +
arch/powerpc/mm/fault.c | 22 +
arch/powerpc/mm/hash64_4k.c | 4 +-
arch/powerpc/mm/hash64_64k.c | 8 +-
arch/powerpc/mm/hash_utils_64.c | 42 +-
arch/powerpc/mm/hugepage-hash64.c | 4 +-
arch/powerpc/mm/hugetlbpage-hash64.c | 5 +-
arch/powerpc/mm/mem.c | 7 +
arch/powerpc/mm/mmu_context_book3s64.c | 5 +
arch/powerpc/mm/mmu_decl.h | 5 +-
arch/powerpc/mm/pkeys.c | 256 +++++
arch/x86/kernel/fpu/xstate.c | 3 +
fs/proc/task_mmu.c | 18 +-
include/linux/mm.h | 18 +-
include/uapi/asm-generic/mman-common.h | 4 +-
tools/testing/selftests/vm/Makefile | 1 +
tools/testing/selftests/vm/pkey-helpers.h | 365 ++++++
tools/testing/selftests/vm/protection_keys.c | 1488 +++++++++++++++++++++++++
tools/testing/selftests/x86/Makefile | 2 +-
tools/testing/selftests/x86/pkey-helpers.h | 219 ----
tools/testing/selftests/x86/protection_keys.c | 1395 -----------------------
46 files changed, 2755 insertions(+), 1755 deletions(-)
create mode 100644 Documentation/vm/protection-keys.txt
delete mode 100644 Documentation/x86/protection-keys.txt
create mode 100644 arch/powerpc/include/asm/pkeys.h
create mode 100644 arch/powerpc/mm/pkeys.c
create mode 100644 tools/testing/selftests/vm/pkey-helpers.h
create mode 100644 tools/testing/selftests/vm/protection_keys.c
delete mode 100644 tools/testing/selftests/x86/pkey-helpers.h
delete mode 100644 tools/testing/selftests/x86/protection_keys.c
--
1.8.3.1
[toc] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-06-27 12:20 +0200 |
| Subject | [RFC v4 09/17] powerpc: call the hash functions with the correct pkey value |
| Message-ID | <tWVLe-7w2-75@gated-at.bofh.it> |
| In reply to | #1675513 |
Pass the correct protection key value to the hash functions on
page fault.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/powerpc/include/asm/pkeys.h | 11 +++++++++++
arch/powerpc/mm/hash_utils_64.c | 4 ++++
arch/powerpc/mm/mem.c | 6 ++++++
3 files changed, 21 insertions(+)
diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
index ef1c601..1370b3f 100644
--- a/arch/powerpc/include/asm/pkeys.h
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -74,6 +74,17 @@ static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
}
/*
+ * return the protection key of the vma corresponding to the
+ * given effective address @ea.
+ */
+static inline int mm_pkey(struct mm_struct *mm, unsigned long ea)
+{
+ struct vm_area_struct *vma = find_vma(mm, ea);
+ int pkey = vma ? vma_pkey(vma) : 0;
+ return pkey;
+}
+
+/*
* Returns a positive, 5-bit key on success, or -1 on failure.
*/
static inline int mm_pkey_alloc(struct mm_struct *mm)
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 7e67dea..403f75d 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -1319,6 +1319,10 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea,
goto bail;
}
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+ pkey = mm_pkey(mm, ea);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
if (hugeshift) {
if (is_thp)
rc = __hash_page_thp(ea, access, vsid, (pmd_t *)ptep,
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index ec890d3..0fcaa48 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -541,8 +541,14 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
return;
}
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+ hash_preload_pkey(vma->vm_mm, address, access, trap, vma_pkey(vma));
+#else
hash_preload(vma->vm_mm, address, access, trap);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
#endif /* CONFIG_PPC_STD_MMU */
+
#if (defined(CONFIG_PPC_BOOK3E_64) || defined(CONFIG_PPC_FSL_BOOK3E)) \
&& defined(CONFIG_HUGETLB_PAGE)
if (is_vm_hugetlb_page(vma))
--
1.8.3.1
[toc] | [prev] | [next] | [standalone]
| From | "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> |
|---|---|
| Date | 2017-06-27 17:30 +0200 |
| Subject | Re: [RFC v4 09/17] powerpc: call the hash functions with the correct pkey value |
| Message-ID | <tX0Bd-2nz-41@gated-at.bofh.it> |
| In reply to | #1675514 |
On Tuesday 27 June 2017 03:41 PM, Ram Pai wrote:
> Pass the correct protection key value to the hash functions on
> page fault.
>
> Signed-off-by: Ram Pai <linuxram@us.ibm.com>
> ---
> arch/powerpc/include/asm/pkeys.h | 11 +++++++++++
> arch/powerpc/mm/hash_utils_64.c | 4 ++++
> arch/powerpc/mm/mem.c | 6 ++++++
> 3 files changed, 21 insertions(+)
>
> diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
> index ef1c601..1370b3f 100644
> --- a/arch/powerpc/include/asm/pkeys.h
> +++ b/arch/powerpc/include/asm/pkeys.h
> @@ -74,6 +74,17 @@ static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
> }
>
> /*
> + * return the protection key of the vma corresponding to the
> + * given effective address @ea.
> + */
> +static inline int mm_pkey(struct mm_struct *mm, unsigned long ea)
> +{
> + struct vm_area_struct *vma = find_vma(mm, ea);
> + int pkey = vma ? vma_pkey(vma) : 0;
> + return pkey;
> +}
> +
> +/*
>
That is not going to work in hash fault path right ? We can't do a
find_vma there without holding the mmap_sem
-aneesh
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-06-28 09:20 +0200 |
| Subject | Re: [RFC v4 09/17] powerpc: call the hash functions with the correct pkey value |
| Message-ID | <tXfqx-3MJ-3@gated-at.bofh.it> |
| In reply to | #1675904 |
On Tue, Jun 27, 2017 at 08:54:07PM +0530, Aneesh Kumar K.V wrote:
>
>
> On Tuesday 27 June 2017 03:41 PM, Ram Pai wrote:
> >Pass the correct protection key value to the hash functions on
> >page fault.
> >
> >Signed-off-by: Ram Pai <linuxram@us.ibm.com>
> >---
> > arch/powerpc/include/asm/pkeys.h | 11 +++++++++++
> > arch/powerpc/mm/hash_utils_64.c | 4 ++++
> > arch/powerpc/mm/mem.c | 6 ++++++
> > 3 files changed, 21 insertions(+)
> >
> >diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
> >index ef1c601..1370b3f 100644
> >--- a/arch/powerpc/include/asm/pkeys.h
> >+++ b/arch/powerpc/include/asm/pkeys.h
> >@@ -74,6 +74,17 @@ static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
> > }
> >
> > /*
> >+ * return the protection key of the vma corresponding to the
> >+ * given effective address @ea.
> >+ */
> >+static inline int mm_pkey(struct mm_struct *mm, unsigned long ea)
> >+{
> >+ struct vm_area_struct *vma = find_vma(mm, ea);
> >+ int pkey = vma ? vma_pkey(vma) : 0;
> >+ return pkey;
> >+}
> >+
> >+/*
> >
>
> That is not going to work in hash fault path right ? We can't do a
> find_vma there without holding the mmap_sem
There is a fundamental problem with this new design. Looks like we can't
hold a lock in that path, without badly hurting the performance.
I am moving back to the old design. Cant by-pass the pte. The
keys will be programmed into the pte which will than be used
to program the hpte.
RP
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-06-27 12:20 +0200 |
| Subject | [RFC v4 02/17] mm: ability to disable execute permission on a key at creation |
| Message-ID | <tWVLf-7w2-81@gated-at.bofh.it> |
| In reply to | #1675513 |
Currently sys_pkey_create() provides the ability to disable read and write permission on the key, at creation. powerpc has the hardware support to disable execute on a pkey as well.This patch enhances the interface to let disable execute at key creation time. x86 does not allow this. Hence the next patch will add ability in x86 to return error if PKEY_DISABLE_EXECUTE is specified. Signed-off-by: Ram Pai <linuxram@us.ibm.com> --- include/uapi/asm-generic/mman-common.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h index 8c27db0..bf4fa07 100644 --- a/include/uapi/asm-generic/mman-common.h +++ b/include/uapi/asm-generic/mman-common.h @@ -74,7 +74,9 @@ #define PKEY_DISABLE_ACCESS 0x1 #define PKEY_DISABLE_WRITE 0x2 +#define PKEY_DISABLE_EXECUTE 0x4 #define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\ - PKEY_DISABLE_WRITE) + PKEY_DISABLE_WRITE |\ + PKEY_DISABLE_EXECUTE) #endif /* __ASM_GENERIC_MMAN_COMMON_H */ -- 1.8.3.1
[toc] | [prev] | [next] | [standalone]
| From | Balbir Singh <bsingharora@gmail.com> |
|---|---|
| Date | 2017-06-27 13:40 +0200 |
| Subject | Re: [RFC v4 02/17] mm: ability to disable execute permission on a key at creation |
| Message-ID | <tWX0B-8iz-13@gated-at.bofh.it> |
| In reply to | #1675516 |
On Tue, 2017-06-27 at 03:11 -0700, Ram Pai wrote: > Currently sys_pkey_create() provides the ability to disable read > and write permission on the key, at creation. powerpc has the > hardware support to disable execute on a pkey as well.This patch > enhances the interface to let disable execute at key creation > time. x86 does not allow this. Hence the next patch will add > ability in x86 to return error if PKEY_DISABLE_EXECUTE is > specified. > > Signed-off-by: Ram Pai <linuxram@us.ibm.com> > --- Acked-by: Balbir Singh <bsingharora@gmail.com>
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-06-27 12:20 +0200 |
| Subject | [RFC v4 15/17] Documentation: Move protecton key documentation to arch neutral directory |
| Message-ID | <tWVLf-7w2-95@gated-at.bofh.it> |
| In reply to | #1675513 |
Since PowerPC and Intel both support memory protection keys, moving the documenation to arch-neutral directory. Signed-off-by: Ram Pai <linuxram@us.ibm.com> --- 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 diff --git a/Documentation/vm/protection-keys.txt b/Documentation/vm/protection-keys.txt new file mode 100644 index 0000000..b643045 --- /dev/null +++ b/Documentation/vm/protection-keys.txt @@ -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. diff --git a/Documentation/x86/protection-keys.txt b/Documentation/x86/protection-keys.txt deleted file mode 100644 index b643045..0000000 --- a/Documentation/x86/protection-keys.txt +++ /dev/null @@ -1,85 +0,0 @@ -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. -- 1.8.3.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-06-27 12:20 +0200 |
| Subject | [RFC v4 03/17] x86: key creation with PKEY_DISABLE_EXECUTE disallowed |
| Message-ID | <tWVLf-7w2-87@gated-at.bofh.it> |
| In reply to | #1675513 |
x86 does not support disabling execute permissions on a pkey. Signed-off-by: Ram Pai <linuxram@us.ibm.com> --- arch/x86/kernel/fpu/xstate.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index c24ac1e..d582631 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -900,6 +900,9 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, if (!boot_cpu_has(X86_FEATURE_OSPKE)) return -EINVAL; + if (init_val & PKEY_DISABLE_EXECUTE) + return -EINVAL; + /* Set the bits we need in PKRU: */ if (init_val & PKEY_DISABLE_ACCESS) new_pkru_bits |= PKRU_AD_BIT; -- 1.8.3.1
[toc] | [prev] | [next] | [standalone]
| From | Balbir Singh <bsingharora@gmail.com> |
|---|---|
| Date | 2017-06-27 13:40 +0200 |
| Subject | Re: [RFC v4 03/17] x86: key creation with PKEY_DISABLE_EXECUTE disallowed |
| Message-ID | <tWX0C-8iz-23@gated-at.bofh.it> |
| In reply to | #1675518 |
On Tue, 2017-06-27 at 03:11 -0700, Ram Pai wrote: > x86 does not support disabling execute permissions on a pkey. > > Signed-off-by: Ram Pai <linuxram@us.ibm.com> > --- > arch/x86/kernel/fpu/xstate.c | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c > index c24ac1e..d582631 100644 > --- a/arch/x86/kernel/fpu/xstate.c > +++ b/arch/x86/kernel/fpu/xstate.c > @@ -900,6 +900,9 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, > if (!boot_cpu_has(X86_FEATURE_OSPKE)) > return -EINVAL; > > + if (init_val & PKEY_DISABLE_EXECUTE) > + return -EINVAL; > + > /* Set the bits we need in PKRU: */ > if (init_val & PKEY_DISABLE_ACCESS) > new_pkru_bits |= PKRU_AD_BIT; I am not an x86 expert. IIUC, execute disable is done via allocating an execute_only_pkey and checking vma_key via AD + vma_flags against VM_EXEC. Your patch looks good to me Acked-by: Balbir Singh <bsingharora@gmail.com> Balbir Singh.
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-06-27 12:20 +0200 |
| Subject | [RFC v4 04/17] powerpc: Implement sys_pkey_alloc and sys_pkey_free system call |
| Message-ID | <tWVLf-7w2-93@gated-at.bofh.it> |
| In reply to | #1675513 |
Sys_pkey_alloc() allocates and returns available pkey
Sys_pkey_free() frees up the pkey.
Total 32 keys are supported on powerpc. However pkey 0,1 and 31
are reserved. So effectively we have 29 pkeys.
Each key can be initialized to disable read, write and execute
permissions. On powerpc a key can be initialize to disable execute.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/powerpc/Kconfig | 15 ++++
arch/powerpc/include/asm/book3s/64/mmu.h | 10 +++
arch/powerpc/include/asm/book3s/64/pgtable.h | 62 ++++++++++++++
arch/powerpc/include/asm/pkeys.h | 124 +++++++++++++++++++++++++++
arch/powerpc/include/asm/systbl.h | 2 +
arch/powerpc/include/asm/unistd.h | 4 +-
arch/powerpc/include/uapi/asm/unistd.h | 2 +
arch/powerpc/mm/Makefile | 1 +
arch/powerpc/mm/mmu_context_book3s64.c | 5 ++
arch/powerpc/mm/pkeys.c | 88 +++++++++++++++++++
10 files changed, 310 insertions(+), 3 deletions(-)
create mode 100644 arch/powerpc/include/asm/pkeys.h
create mode 100644 arch/powerpc/mm/pkeys.c
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index f7c8f99..81202e5 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -871,6 +871,21 @@ config SECCOMP
If unsure, say Y. Only embedded should say N here.
+config PPC64_MEMORY_PROTECTION_KEYS
+ prompt "PowerPC Memory Protection Keys"
+ def_bool y
+ # Note: only available in 64-bit mode
+ depends on PPC64
+ select ARCH_USES_HIGH_VMA_FLAGS
+ select ARCH_HAS_PKEYS
+ ---help---
+ 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.
+
+ For details, see Documentation/powerpc/protection-keys.txt
+
+ If unsure, say y.
endmenu
config ISA_DMA_API
diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h
index 77529a3..0c0a2a8 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu.h
@@ -108,6 +108,16 @@ struct patb_entry {
#ifdef CONFIG_SPAPR_TCE_IOMMU
struct list_head iommu_group_mem_list;
#endif
+
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+ /*
+ * Each bit represents one protection key.
+ * bit set -> key allocated
+ * bit unset -> key available for allocation
+ */
+ u32 pkey_allocation_map;
+ s16 execute_only_pkey; /* key holding execute-only protection */
+#endif
} mm_context_t;
/*
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 85bc987..87e9a89 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -428,6 +428,68 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
pte_update(mm, addr, ptep, 0, _PAGE_PRIVILEGED, 1);
}
+
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+
+#include <asm/reg.h>
+static inline u64 read_amr(void)
+{
+ return mfspr(SPRN_AMR);
+}
+static inline void write_amr(u64 value)
+{
+ mtspr(SPRN_AMR, value);
+}
+static inline u64 read_iamr(void)
+{
+ return mfspr(SPRN_IAMR);
+}
+static inline void write_iamr(u64 value)
+{
+ mtspr(SPRN_IAMR, value);
+}
+static inline u64 read_uamor(void)
+{
+ return mfspr(SPRN_UAMOR);
+}
+static inline void write_uamor(u64 value)
+{
+ mtspr(SPRN_UAMOR, value);
+}
+
+#else /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
+static inline u64 read_amr(void)
+{
+ WARN(1, "%s called with MEMORY PROTECTION KEYS disabled\n", __func__);
+ return -1;
+}
+static inline void write_amr(u64 value)
+{
+ WARN(1, "%s called with MEMORY PROTECTION KEYS disabled\n", __func__);
+}
+static inline u64 read_uamor(void)
+{
+ WARN(1, "%s called with MEMORY PROTECTION KEYS disabled\n", __func__);
+ return -1;
+}
+static inline void write_uamor(u64 value)
+{
+ WARN(1, "%s called with MEMORY PROTECTION KEYS disabled\n", __func__);
+}
+static inline u64 read_iamr(void)
+{
+ WARN(1, "%s called with MEMORY PROTECTION KEYS disabled\n", __func__);
+ return -1;
+}
+static inline void write_iamr(u64 value)
+{
+ WARN(1, "%s called with MEMORY PROTECTION KEYS disabled\n", __func__);
+}
+
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
+
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
new file mode 100644
index 0000000..7bc8746
--- /dev/null
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -0,0 +1,124 @@
+#ifndef _ASM_PPC64_PKEYS_H
+#define _ASM_PPC64_PKEYS_H
+
+
+#define arch_max_pkey() 32
+
+#define AMR_AD_BIT 0x1UL
+#define AMR_WD_BIT 0x2UL
+#define IAMR_EX_BIT 0x1UL
+#define AMR_BITS_PER_PKEY 2
+#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | \
+ VM_PKEY_BIT1 | \
+ VM_PKEY_BIT2 | \
+ VM_PKEY_BIT3 | \
+ VM_PKEY_BIT4)
+
+/*
+ * Bits are in BE format.
+ * NOTE: key 31, 1, 0 are not used.
+ * key 0 is used by default. It give read/write/execute permission.
+ * key 31 is reserved by the hypervisor.
+ * key 1 is recommended to be not used.
+ * PowerISA(3.0) page 1015, programming note.
+ */
+#define PKEY_INITIAL_ALLOCAION 0xc0000001
+
+#define pkeybit_mask(pkey) (0x1 << (arch_max_pkey() - pkey - 1))
+
+#define mm_pkey_allocation_map(mm) (mm->context.pkey_allocation_map)
+
+#define mm_set_pkey_allocated(mm, pkey) { \
+ mm_pkey_allocation_map(mm) |= pkeybit_mask(pkey); \
+}
+
+#define mm_set_pkey_free(mm, pkey) { \
+ mm_pkey_allocation_map(mm) &= ~pkeybit_mask(pkey); \
+}
+
+#define mm_set_pkey_is_allocated(mm, pkey) \
+ (mm_pkey_allocation_map(mm) & pkeybit_mask(pkey))
+
+#define mm_set_pkey_is_reserved(mm, pkey) (PKEY_INITIAL_ALLOCAION & \
+ pkeybit_mask(pkey))
+
+static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
+{
+ /* a reserved key is never considered as 'explicitly allocated' */
+ return (!mm_set_pkey_is_reserved(mm, pkey) &&
+ mm_set_pkey_is_allocated(mm, pkey));
+}
+
+/*
+ * Returns a positive, 5-bit key on success, or -1 on failure.
+ */
+static inline int mm_pkey_alloc(struct mm_struct *mm)
+{
+ /*
+ * Note: this is the one and only place we make sure
+ * that the pkey is valid as far as the hardware is
+ * concerned. The rest of the kernel trusts that
+ * only good, valid pkeys come out of here.
+ */
+ u32 all_pkeys_mask = (u32)(~(0x0));
+ int ret;
+
+ /*
+ * Are we out of pkeys? We must handle this specially
+ * because ffz() behavior is undefined if there are no
+ * zeros.
+ */
+ if (mm_pkey_allocation_map(mm) == all_pkeys_mask)
+ return -1;
+
+ ret = arch_max_pkey() -
+ ffz((u32)mm_pkey_allocation_map(mm))
+ - 1;
+ mm_set_pkey_allocated(mm, ret);
+ return ret;
+}
+
+static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
+{
+ if (!mm_pkey_is_allocated(mm, pkey))
+ return -EINVAL;
+
+ mm_set_pkey_free(mm, pkey);
+
+ return 0;
+}
+
+/*
+ * Try to dedicate one of the protection keys to be used as an
+ * execute-only protection key.
+ */
+extern int __execute_only_pkey(struct mm_struct *mm);
+static inline int execute_only_pkey(struct mm_struct *mm)
+{
+ return __execute_only_pkey(mm);
+}
+
+extern int __arch_override_mprotect_pkey(struct vm_area_struct *vma,
+ int prot, int pkey);
+static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
+ int prot, int pkey)
+{
+ return __arch_override_mprotect_pkey(vma, prot, pkey);
+}
+
+extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+ unsigned long init_val);
+static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+ unsigned long init_val)
+{
+ return __arch_set_user_pkey_access(tsk, pkey, init_val);
+}
+
+static inline pkey_mm_init(struct mm_struct *mm)
+{
+ mm_pkey_allocation_map(mm) = PKEY_INITIAL_ALLOCAION;
+ /* -1 means unallocated or invalid */
+ mm->context.execute_only_pkey = -1;
+}
+
+#endif /*_ASM_PPC64_PKEYS_H */
diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h
index 1c94708..22dd776 100644
--- a/arch/powerpc/include/asm/systbl.h
+++ b/arch/powerpc/include/asm/systbl.h
@@ -388,3 +388,5 @@
COMPAT_SYS_SPU(pwritev2)
SYSCALL(kexec_file_load)
SYSCALL(statx)
+SYSCALL(pkey_alloc)
+SYSCALL(pkey_free)
diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h
index 9ba11db..e0273bc 100644
--- a/arch/powerpc/include/asm/unistd.h
+++ b/arch/powerpc/include/asm/unistd.h
@@ -12,13 +12,11 @@
#include <uapi/asm/unistd.h>
-#define NR_syscalls 384
+#define NR_syscalls 386
#define __NR__exit __NR_exit
#define __IGNORE_pkey_mprotect
-#define __IGNORE_pkey_alloc
-#define __IGNORE_pkey_free
#ifndef __ASSEMBLY__
diff --git a/arch/powerpc/include/uapi/asm/unistd.h b/arch/powerpc/include/uapi/asm/unistd.h
index b85f142..7993a07 100644
--- a/arch/powerpc/include/uapi/asm/unistd.h
+++ b/arch/powerpc/include/uapi/asm/unistd.h
@@ -394,5 +394,7 @@
#define __NR_pwritev2 381
#define __NR_kexec_file_load 382
#define __NR_statx 383
+#define __NR_pkey_alloc 384
+#define __NR_pkey_free 385
#endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 7414034..8cc2ff1 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -45,3 +45,4 @@ obj-$(CONFIG_PPC_COPRO_BASE) += copro_fault.o
obj-$(CONFIG_SPAPR_TCE_IOMMU) += mmu_context_iommu.o
obj-$(CONFIG_PPC_PTDUMP) += dump_linuxpagetables.o
obj-$(CONFIG_PPC_HTDUMP) += dump_hashpagetable.o
+obj-$(CONFIG_PPC64_MEMORY_PROTECTION_KEYS) += pkeys.o
diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c
index c6dca2a..2da9931 100644
--- a/arch/powerpc/mm/mmu_context_book3s64.c
+++ b/arch/powerpc/mm/mmu_context_book3s64.c
@@ -16,6 +16,7 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/mm.h>
+#include <linux/pkeys.h>
#include <linux/spinlock.h>
#include <linux/idr.h>
#include <linux/export.h>
@@ -120,6 +121,10 @@ static int hash__init_new_context(struct mm_struct *mm)
subpage_prot_init_new_context(mm);
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+ pkey_mm_init(mm);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
return index;
}
diff --git a/arch/powerpc/mm/pkeys.c b/arch/powerpc/mm/pkeys.c
new file mode 100644
index 0000000..b97366e
--- /dev/null
+++ b/arch/powerpc/mm/pkeys.c
@@ -0,0 +1,88 @@
+/*
+ * PowerPC Memory Protection Keys management
+ * Copyright (c) 2015, Intel Corporation.
+ * Copyright (c) 2017, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+#include <linux/pkeys.h> /* PKEY_* */
+#include <uapi/asm-generic/mman-common.h>
+
+
+/*
+ * set the access right in AMR IAMR and UAMOR register
+ * for @pkey to that specified in @init_val.
+ */
+int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+ unsigned long init_val)
+{
+ u64 old_amr, old_uamor, old_iamr;
+ int pkey_shift = (arch_max_pkey()-pkey-1) * AMR_BITS_PER_PKEY;
+ u64 new_amr_bits = 0x0ul;
+ u64 new_iamr_bits = 0x0ul;
+ u64 new_uamor_bits = 0x3ul;
+
+ /* Set the bits we need in AMR: */
+ if (init_val & PKEY_DISABLE_ACCESS)
+ new_amr_bits |= AMR_AD_BIT;
+ if (init_val & PKEY_DISABLE_WRITE)
+ new_amr_bits |= AMR_WD_BIT;
+
+ /*
+ * By default execute is disabled.
+ * To enable execute, PKEY_ENABLE_EXECUTE
+ * needs to be specified.
+ */
+ if ((init_val & PKEY_DISABLE_EXECUTE))
+ new_iamr_bits |= IAMR_EX_BIT;
+
+ /* Shift the bits in to the correct place in AMR for pkey: */
+ new_amr_bits <<= pkey_shift;
+ new_iamr_bits <<= pkey_shift;
+ new_uamor_bits <<= pkey_shift;
+
+ /* Get old AMR and mask off any old bits in place: */
+ old_amr = read_amr();
+ old_amr &= ~((u64)(AMR_AD_BIT|AMR_WD_BIT) << pkey_shift);
+
+ old_iamr = read_iamr();
+ old_iamr &= ~(0x3ul << pkey_shift);
+
+ old_uamor = read_uamor();
+ old_uamor &= ~(0x3ul << pkey_shift);
+
+ /* Write old part along with new part: */
+ write_amr(old_amr | new_amr_bits);
+ write_iamr(old_iamr | new_iamr_bits);
+ write_uamor(old_uamor | new_uamor_bits);
+
+ return 0;
+}
+
+int __execute_only_pkey(struct mm_struct *mm)
+{
+ return -1;
+}
+
+/*
+ * This should only be called for *plain* mprotect calls.
+ */
+int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot,
+ int pkey)
+{
+ /*
+ * Is this an mprotect_pkey() call? If so, never
+ * override the value that came from the user.
+ */
+ if (pkey != -1)
+ return pkey;
+
+ return 0;
+}
--
1.8.3.1
[toc] | [prev] | [next] | [standalone]
| From | Balbir Singh <bsingharora@gmail.com> |
|---|---|
| Date | 2017-06-27 12:50 +0200 |
| Message-ID | <tWWee-7HI-13@gated-at.bofh.it> |
| In reply to | #1675513 |
On Tue, 2017-06-27 at 03:11 -0700, Ram Pai wrote: > Memory protection keys enable applications to protect its > address space from inadvertent access or corruption from > itself. > > The overall idea: > > A process allocates a key and associates it with > a address range within its address space. > The process than can dynamically set read/write > permissions on the key without involving the > kernel. Any code that violates the permissions > off the address space; as defined by its associated > key, will receive a segmentation fault. > > This patch series enables the feature on PPC64 HPTE > platform. > > ISA3.0 section 5.7.13 describes the detailed specifications. > > > Testing: > This patch series has passed all the protection key > tests available in the selftests directory. > The tests are updated to work on both x86 and powerpc. > > version v4: > (1) patches no more depend on the pte bits to program > the hpte -- comment by Balbir > (2) documentation updates > (3) fixed a bug in the selftest. > (4) unlike x86, powerpc lets signal handler change key > permission bits; the change will persist across > signal handler boundaries. Earlier we allowed > the signal handler to modify a field in the siginfo > structure which would than be used by the kernel > to program the key protection register (AMR) > -- resolves a issue raised by Ben. > "Calls to sys_swapcontext with a made-up context > will end up with a crap AMR if done by code who > didn't know about that register". > (5) these changes enable protection keys on 4k-page > kernel aswell. I have not looked at the full series, but it seems cleaner than the original one and the side-effect is that we can support 4k as well. Nice! Balbir Singh.
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web