Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1234373 > unrolled thread

[PATCH 00/25] x86: Memory Protection Keys

Started byDave Hansen <dave@sr71.net>
First post2015-09-28 21:30 +0200
Last post2015-09-28 21:30 +0200
Articles 12 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 00/25] x86: Memory Protection Keys Dave Hansen <dave@sr71.net> - 2015-09-28 21:30 +0200
    [PATCH 21/25] mm: implement new mprotect_key() system call Dave Hansen <dave@sr71.net> - 2015-09-28 21:30 +0200
      Re: [PATCH 21/25] mm: implement new mprotect_key() system call Michael Ellerman <mpe@ellerman.id.au> - 2015-09-29 08:40 +0200
        Re: [PATCH 21/25] mm: implement new mprotect_key() system call Dave Hansen <dave@sr71.net> - 2015-09-29 16:20 +0200
    [PATCH 07/25] x86, pkeys: new page fault error code bit: PF_PK Dave Hansen <dave@sr71.net> - 2015-09-28 21:30 +0200
      Re: [PATCH 07/25] x86, pkeys: new page fault error code bit: PF_PK Thomas Gleixner <tglx@linutronix.de> - 2015-10-01 14:00 +0200
        Re: [PATCH 07/25] x86, pkeys: new page fault error code bit: PF_PK Dave Hansen <dave@sr71.net> - 2015-10-01 19:20 +0200
    [PATCH 16/25] x86, pkeys: optimize fault handling in access_error() Dave Hansen <dave@sr71.net> - 2015-09-28 21:30 +0200
    [PATCH 13/25] mm: factor out VMA fault permission checking Dave Hansen <dave@sr71.net> - 2015-09-28 21:30 +0200
    [PATCH 08/25] x86, pkeys: store protection in high VMA flags Dave Hansen <dave@sr71.net> - 2015-09-28 21:30 +0200
    [PATCH 06/25] x86, pkeys: PTE bits for storing protection key Dave Hansen <dave@sr71.net> - 2015-09-28 21:30 +0200
    [PATCH 14/25] mm: simplify get_user_pages() PTE bit handling Dave Hansen <dave@sr71.net> - 2015-09-28 21:30 +0200

#1234373 — [PATCH 00/25] x86: Memory Protection Keys

FromDave Hansen <dave@sr71.net>
Date2015-09-28 21:30 +0200
Subject[PATCH 00/25] x86: Memory Protection Keys
Message-ID<qdM7T-59-3@gated-at.bofh.it>
I have addressed all known issues and review comments.  I believe
they are ready to be pulled in to the x86 tree.  Note that this
is also the first time anyone has seen the new 'selftests' code.
If there are issues limited to it, I'd prefer to fix those up
separately post-merge.

Changes from RFCv2 (Thanks Ingo and Thomas for most of these):

 * few minor compile warnings
 * changed 'nopku' interaction with cpuid bits.  Now, we do not
   clear the PKU cpuid bit, we just skip enabling it.
 * changed __pkru_allows_write() to also check access disable bit
 * removed the unused write_pkru()
 * made si_pkey a u64 and added some patch description details.
   Also made it share space in siginfo with MPX and clarified
   comments.
 * give some real text for the Processor Trace xsave state
 * made vma_pkey() less ugly (and much more optimized actually)
 * added SEGV_PKUERR to copy_siginfo_to_user()
 * remove page table walk when filling in si_pkey, added some
   big fat comments about it being inherently racy.
 * added self test code

MM reviewers, if you are going to look at one thing, please look
at patch 14 which adds a bunch of additional vma/pte permission
checks.

This code contains a new system call: mprotect_key(),  This needs
the usual amount of rigor around new interfaces.  Review there
would be much appreciated.

This code is not runnable to anyone outside of Intel unless they
have some special hardware or a fancy simulator.  If you are
interested in running this for real, please get in touch with me.
Hardware is available to a very small but nonzero number of
people.

This set is also available here (with the new syscall):

	git://git.kernel.org/pub/scm/linux/kernel/git/daveh/x86-pkeys.git pkeys-v006

=== diffstat ===

(note that over half of this is kselftests)

 Documentation/kernel-parameters.txt           |    3 
 Documentation/x86/protection-keys.txt         |   54 +
 arch/powerpc/include/asm/mman.h               |    5 
 arch/powerpc/include/asm/mmu_context.h        |   11 
 arch/s390/include/asm/mmu_context.h           |   11 
 arch/unicore32/include/asm/mmu_context.h      |   11 
 arch/x86/Kconfig                              |   15 
 arch/x86/entry/syscalls/syscall_32.tbl        |    1 
 arch/x86/entry/syscalls/syscall_64.tbl        |    1 
 arch/x86/include/asm/cpufeature.h             |   54 +
 arch/x86/include/asm/disabled-features.h      |   12 
 arch/x86/include/asm/fpu/types.h              |   16 
 arch/x86/include/asm/fpu/xstate.h             |    4 
 arch/x86/include/asm/mmu_context.h            |   71 ++
 arch/x86/include/asm/pgtable.h                |   45 +
 arch/x86/include/asm/pgtable_types.h          |   34 -
 arch/x86/include/asm/required-features.h      |    4 
 arch/x86/include/asm/special_insns.h          |   32 +
 arch/x86/include/uapi/asm/mman.h              |   23 
 arch/x86/include/uapi/asm/processor-flags.h   |    2 
 arch/x86/kernel/cpu/common.c                  |   42 +
 arch/x86/kernel/fpu/xstate.c                  |    7 
 arch/x86/kernel/process_64.c                  |    2 
 arch/x86/kernel/setup.c                       |    9 
 arch/x86/mm/fault.c                           |  143 +++-
 arch/x86/mm/gup.c                             |   37 -
 drivers/char/agp/frontend.c                   |    2 
 drivers/staging/android/ashmem.c              |    9 
 fs/proc/task_mmu.c                            |    5 
 include/asm-generic/mm_hooks.h                |   11 
 include/linux/mm.h                            |   13 
 include/linux/mman.h                          |    6 
 include/uapi/asm-generic/siginfo.h            |   17 
 kernel/signal.c                               |    4 
 mm/Kconfig                                    |   11 
 mm/gup.c                                      |   28 
 mm/memory.c                                   |    4 
 mm/mmap.c                                     |    2 
 mm/mprotect.c                                 |   20 
 mm/nommu.c                                    |    2 
 tools/testing/selftests/x86/Makefile          |    3 
 tools/testing/selftests/x86/pkey-helpers.h    |  182 +++++
 tools/testing/selftests/x86/protection_keys.c |  828 ++++++++++++++++++++++++++
 43 files changed, 1705 insertions(+), 91 deletions(-)

Cc: linux-api@vger.kernel.org
Cc: linux-arch@vger.kernel.org
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1234374 — [PATCH 21/25] mm: implement new mprotect_key() system call

FromDave Hansen <dave@sr71.net>
Date2015-09-28 21:30 +0200
Subject[PATCH 21/25] mm: implement new mprotect_key() system call
Message-ID<qdMhB-gH-43@gated-at.bofh.it>
In reply to#1234373
From: Dave Hansen <dave.hansen@linux.intel.com>

mprotect_key() is just like mprotect, except it also takes a
protection key as an argument.  On systems that do not support
protection keys, it still works, but requires that key=0.
Otherwise it does exactly what mprotect does.

I expect it to get used like this, if you want to guarantee that
any mapping you create can *never* be accessed without the right
protection keys set up.

	pkey_deny_access(11); // random pkey
	int real_prot = PROT_READ|PROT_WRITE;
	ptr = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
	ret = mprotect_key(ptr, PAGE_SIZE, real_prot, 11);

This way, there is *no* window where the mapping is accessible
since it was always either PROT_NONE or had a protection key set.

We settled on 'unsigned long' for the type of the key here.  We
only need 4 bits on x86 today, but I figured that other
architectures might need some more space.

Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: linux-api@vger.kernel.org
---

 b/mm/Kconfig    |    7 +++++++
 b/mm/mprotect.c |   20 +++++++++++++++++---
 2 files changed, 24 insertions(+), 3 deletions(-)

diff -puN mm/Kconfig~pkeys-85-mprotect_pkey mm/Kconfig
--- a/mm/Kconfig~pkeys-85-mprotect_pkey	2015-09-28 11:39:50.527391162 -0700
+++ b/mm/Kconfig	2015-09-28 11:39:50.532391390 -0700
@@ -683,3 +683,10 @@ config FRAME_VECTOR
 
 config ARCH_USES_HIGH_VMA_FLAGS
 	bool
+
+config NR_PROTECTION_KEYS
+	int
+	# Everything supports a _single_ key, so allow folks to
+	# at least call APIs that take keys, but require that the
+	# key be 0.
+	default 1
diff -puN mm/mprotect.c~pkeys-85-mprotect_pkey mm/mprotect.c
--- a/mm/mprotect.c~pkeys-85-mprotect_pkey	2015-09-28 11:39:50.529391253 -0700
+++ b/mm/mprotect.c	2015-09-28 11:39:50.532391390 -0700
@@ -344,8 +344,8 @@ fail:
 	return error;
 }
 
-SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
-		unsigned long, prot)
+static int do_mprotect_key(unsigned long start, size_t len,
+		unsigned long prot, unsigned long key)
 {
 	unsigned long vm_flags, nstart, end, tmp, reqprot;
 	struct vm_area_struct *vma, *prev;
@@ -365,6 +365,8 @@ SYSCALL_DEFINE3(mprotect, unsigned long,
 		return -ENOMEM;
 	if (!arch_validate_prot(prot))
 		return -EINVAL;
+	if (key >= CONFIG_NR_PROTECTION_KEYS)
+		return -EINVAL;
 
 	reqprot = prot;
 	/*
@@ -373,7 +375,7 @@ SYSCALL_DEFINE3(mprotect, unsigned long,
 	if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
 		prot |= PROT_EXEC;
 
-	vm_flags = calc_vm_prot_bits(prot, 0);
+	vm_flags = calc_vm_prot_bits(prot, key);
 
 	down_write(&current->mm->mmap_sem);
 
@@ -443,3 +445,15 @@ out:
 	up_write(&current->mm->mmap_sem);
 	return error;
 }
+
+SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
+		unsigned long, prot)
+{
+	return do_mprotect_key(start, len, prot, 0);
+}
+
+SYSCALL_DEFINE4(mprotect_key, unsigned long, start, size_t, len,
+		unsigned long, prot, unsigned long, key)
+{
+	return do_mprotect_key(start, len, prot, key);
+}
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1234741 — Re: [PATCH 21/25] mm: implement new mprotect_key() system call

FromMichael Ellerman <mpe@ellerman.id.au>
Date2015-09-29 08:40 +0200
SubjectRe: [PATCH 21/25] mm: implement new mprotect_key() system call
Message-ID<qdWJY-6XG-11@gated-at.bofh.it>
In reply to#1234374
On Mon, 2015-09-28 at 12:18 -0700, Dave Hansen wrote:
> From: Dave Hansen <dave.hansen@linux.intel.com>
> 
> mprotect_key() is just like mprotect, except it also takes a
> protection key as an argument.  On systems that do not support
> protection keys, it still works, but requires that key=0.

I'm not sure how userspace is going to use the key=0 feature? ie. userspace
will still have to detect that keys are not supported and use key 0 everywhere.
At that point it could just as well skip the mprotect_key() syscalls entirely
couldn't it?

> I expect it to get used like this, if you want to guarantee that
> any mapping you create can *never* be accessed without the right
> protection keys set up.
> 
> 	pkey_deny_access(11); // random pkey
> 	int real_prot = PROT_READ|PROT_WRITE;
> 	ptr = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
> 	ret = mprotect_key(ptr, PAGE_SIZE, real_prot, 11);
> 
> This way, there is *no* window where the mapping is accessible
> since it was always either PROT_NONE or had a protection key set.
> 
> We settled on 'unsigned long' for the type of the key here.  We
> only need 4 bits on x86 today, but I figured that other
> architectures might need some more space.

If the existing mprotect() syscall had a flags argument you could have just
used that. So is it worth just adding mprotect2() now and using it for this? ie:

int mprotect2(unsigned long start, size_t len, unsigned long prot, unsigned long flags) ..

And then you define bit zero of flags to say you're passing a pkey, and it's in
bits 1-63?

That way if other arches need to do something different you at least have the
flags available?

cheers


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1235145 — Re: [PATCH 21/25] mm: implement new mprotect_key() system call

FromDave Hansen <dave@sr71.net>
Date2015-09-29 16:20 +0200
SubjectRe: [PATCH 21/25] mm: implement new mprotect_key() system call
Message-ID<qe3V9-rR-15@gated-at.bofh.it>
In reply to#1234741
On 09/28/2015 11:39 PM, Michael Ellerman wrote:
> On Mon, 2015-09-28 at 12:18 -0700, Dave Hansen wrote:
>> From: Dave Hansen <dave.hansen@linux.intel.com>
>>
>> mprotect_key() is just like mprotect, except it also takes a
>> protection key as an argument.  On systems that do not support
>> protection keys, it still works, but requires that key=0.
> 
> I'm not sure how userspace is going to use the key=0 feature? ie. userspace
> will still have to detect that keys are not supported and use key 0 everywhere.
> At that point it could just as well skip the mprotect_key() syscalls entirely
> couldn't it?

Yep.

Or, a new architecture could just skip mprotect() itself entirely and
only wire up mprotect_pkey().  I don't see this pkey=0 thing as an
important feature or anything.  I just wanted to call out the behavior.

>> I expect it to get used like this, if you want to guarantee that
>> any mapping you create can *never* be accessed without the right
>> protection keys set up.
>>
>> 	pkey_deny_access(11); // random pkey
>> 	int real_prot = PROT_READ|PROT_WRITE;
>> 	ptr = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
>> 	ret = mprotect_key(ptr, PAGE_SIZE, real_prot, 11);
>>
>> This way, there is *no* window where the mapping is accessible
>> since it was always either PROT_NONE or had a protection key set.
>>
>> We settled on 'unsigned long' for the type of the key here.  We
>> only need 4 bits on x86 today, but I figured that other
>> architectures might need some more space.
> 
> If the existing mprotect() syscall had a flags argument you could have just
> used that. So is it worth just adding mprotect2() now and using it for this? ie:
> 
> int mprotect2(unsigned long start, size_t len, unsigned long prot, unsigned long flags) ..
> 
> And then you define bit zero of flags to say you're passing a pkey, and it's in
> bits 1-63?
> 
> That way if other arches need to do something different you at least have the
> flags available?

But what problem does that solve?

mprotect() itself has plenty of space in prot.  Do any of the other
architectures need to pass in more than just an integer key to implement
storage/protection keys?

I'd much rather have a set of (relatively) arch-specific system calls
implementing protection keys rather than a single one with one
arch-specific argument.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1234375 — [PATCH 07/25] x86, pkeys: new page fault error code bit: PF_PK

FromDave Hansen <dave@sr71.net>
Date2015-09-28 21:30 +0200
Subject[PATCH 07/25] x86, pkeys: new page fault error code bit: PF_PK
Message-ID<qdMhB-gH-41@gated-at.bofh.it>
In reply to#1234373
From: Dave Hansen <dave.hansen@linux.intel.com>

Note: "PK" is how the Intel SDM refers to this bit, so we also
use that nomenclature.

This only defines the bit, it does not plumb it anywhere to be
handled.

Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---

 b/arch/x86/mm/fault.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff -puN arch/x86/mm/fault.c~pkeys-05-pfec arch/x86/mm/fault.c
--- a/arch/x86/mm/fault.c~pkeys-05-pfec	2015-09-28 11:39:44.073097565 -0700
+++ b/arch/x86/mm/fault.c	2015-09-28 11:39:44.076097701 -0700
@@ -33,6 +33,7 @@
  *   bit 2 ==	 0: kernel-mode access	1: user-mode access
  *   bit 3 ==				1: use of reserved bit detected
  *   bit 4 ==				1: fault was an instruction fetch
+ *   bit 5 ==				1: protection keys block access
  */
 enum x86_pf_error_code {
 
@@ -41,6 +42,7 @@ enum x86_pf_error_code {
 	PF_USER		=		1 << 2,
 	PF_RSVD		=		1 << 3,
 	PF_INSTR	=		1 << 4,
+	PF_PK		=		1 << 5,
 };
 
 /*
@@ -916,7 +918,10 @@ static int spurious_fault_check(unsigned
 
 	if ((error_code & PF_INSTR) && !pte_exec(*pte))
 		return 0;
-
+	/*
+	 * Note: We do not do lazy flushing on protection key
+	 * changes, so no spurious fault will ever set PF_PK.
+	 */
 	return 1;
 }
 
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1237312 — Re: [PATCH 07/25] x86, pkeys: new page fault error code bit: PF_PK

FromThomas Gleixner <tglx@linutronix.de>
Date2015-10-01 14:00 +0200
SubjectRe: [PATCH 07/25] x86, pkeys: new page fault error code bit: PF_PK
Message-ID<qeKGK-383-1@gated-at.bofh.it>
In reply to#1234375
On Mon, 28 Sep 2015, Dave Hansen wrote:
>  
>  /*
> @@ -916,7 +918,10 @@ static int spurious_fault_check(unsigned
>  
>  	if ((error_code & PF_INSTR) && !pte_exec(*pte))
>  		return 0;
> -
> +	/*
> +	 * Note: We do not do lazy flushing on protection key
> +	 * changes, so no spurious fault will ever set PF_PK.
> +	 */

It might be a bit more clear to have:

   	/* Comment .... */
  	if ((error_code & PF_PK))
  		return 1;

  	return 1;

That way the comment is associated to obviously redundant code, but
it's easier to read, especially if we add some new PF_ thingy after
that.

Other than that:

Reviewed-by: Thomas Gleixner <tglx@linutronix.de>


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1237582 — Re: [PATCH 07/25] x86, pkeys: new page fault error code bit: PF_PK

FromDave Hansen <dave@sr71.net>
Date2015-10-01 19:20 +0200
SubjectRe: [PATCH 07/25] x86, pkeys: new page fault error code bit: PF_PK
Message-ID<qePGq-2Bk-19@gated-at.bofh.it>
In reply to#1237312
On 10/01/2015 04:54 AM, Thomas Gleixner wrote:
> On Mon, 28 Sep 2015, Dave Hansen wrote:
>> >  
>> >  /*
>> > @@ -916,7 +918,10 @@ static int spurious_fault_check(unsigned
>> >  
>> >  	if ((error_code & PF_INSTR) && !pte_exec(*pte))
>> >  		return 0;
>> > -
>> > +	/*
>> > +	 * Note: We do not do lazy flushing on protection key
>> > +	 * changes, so no spurious fault will ever set PF_PK.
>> > +	 */
> It might be a bit more clear to have:
> 
>    	/* Comment .... */
>   	if ((error_code & PF_PK))
>   		return 1;
> 
>   	return 1;
> 
> That way the comment is associated to obviously redundant code, but
> it's easier to read, especially if we add some new PF_ thingy after
> that.

Agreed, that's a nicer way to do it.  I'll fix it up.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1234376 — [PATCH 16/25] x86, pkeys: optimize fault handling in access_error()

FromDave Hansen <dave@sr71.net>
Date2015-09-28 21:30 +0200
Subject[PATCH 16/25] x86, pkeys: optimize fault handling in access_error()
Message-ID<qdMhB-gH-49@gated-at.bofh.it>
In reply to#1234373
From: Dave Hansen <dave.hansen@linux.intel.com>

We might not strictly have to make modifictions to
access_error() to check the VMA here.

If we do not, we will do this:
1. app sets VMA pkey to K
2. app touches a !present page
3. do_page_fault(), allocates and maps page, sets pte.pkey=K
4. return to userspace
5. touch instruction reexecutes, but triggers PF_PK
6. do PKEY signal

What happens with this patch applied:
1. app sets VMA pkey to K
2. app touches a !present page
3. do_page_fault() notices that K is inaccessible
4. do PKEY signal

We basically skip the fault that does an allocation.

So what this lets us do is protect areas from even being
*populated* unless it is accessible according to protection
keys.  That seems handy to me and makes protection keys work
more like an mprotect()'d mapping.

Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---

 b/arch/x86/mm/fault.c |   10 ++++++++++
 1 file changed, 10 insertions(+)

diff -puN arch/x86/mm/fault.c~pkeys-15-access_error arch/x86/mm/fault.c
--- a/arch/x86/mm/fault.c~pkeys-15-access_error	2015-09-28 11:39:48.287289263 -0700
+++ b/arch/x86/mm/fault.c	2015-09-28 11:39:48.290289400 -0700
@@ -904,6 +904,9 @@ static inline bool bad_area_access_from_
 		return false;
 	if (error_code & PF_PK)
 		return true;
+	/* this checks permission keys on the VMA: */
+	if (!arch_vma_access_permitted(vma, (error_code & PF_WRITE)))
+		return true;
 	return false;
 }
 
@@ -1091,6 +1094,13 @@ access_error(unsigned long error_code, s
 	 */
 	if (error_code & PF_PK)
 		return 1;
+	/*
+	 * Make sure to check the VMA so that we do not perform
+	 * faults just to hit a PF_PK as soon as we fill in a
+	 * page.
+	 */
+	if (!arch_vma_access_permitted(vma, (error_code & PF_WRITE)))
+		return 1;
 
 	if (error_code & PF_WRITE) {
 		/* write, present and write, not present: */
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1234377 — [PATCH 13/25] mm: factor out VMA fault permission checking

FromDave Hansen <dave@sr71.net>
Date2015-09-28 21:30 +0200
Subject[PATCH 13/25] mm: factor out VMA fault permission checking
Message-ID<qdMhB-gH-51@gated-at.bofh.it>
In reply to#1234373
From: Dave Hansen <dave.hansen@linux.intel.com>

This code matches a fault condition up with the VMA and ensures
that the VMA allows the fault to be handled instead of just
erroring out.

We will be extending this in a moment to comprehend protection
keys.

Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---

 b/mm/gup.c |   15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff -puN mm/gup.c~pkeys-10-pte-fault mm/gup.c
--- a/mm/gup.c~pkeys-10-pte-fault	2015-09-28 11:39:46.790221164 -0700
+++ b/mm/gup.c	2015-09-28 11:39:46.794221345 -0700
@@ -554,6 +554,17 @@ next_page:
 }
 EXPORT_SYMBOL(__get_user_pages);
 
+bool vma_permits_fault(struct vm_area_struct *vma, unsigned int fault_flags)
+{
+        vm_flags_t vm_flags =
+		(fault_flags & FAULT_FLAG_WRITE) ? VM_WRITE : VM_READ;
+
+	if (!(vm_flags & vma->vm_flags))
+		return false;
+
+	return true;
+}
+
 /*
  * fixup_user_fault() - manually resolve a user page fault
  * @tsk:	the task_struct to use for page fault accounting, or
@@ -585,15 +596,13 @@ int fixup_user_fault(struct task_struct
 		     unsigned long address, unsigned int fault_flags)
 {
 	struct vm_area_struct *vma;
-	vm_flags_t vm_flags;
 	int ret;
 
 	vma = find_extend_vma(mm, address);
 	if (!vma || address < vma->vm_start)
 		return -EFAULT;
 
-	vm_flags = (fault_flags & FAULT_FLAG_WRITE) ? VM_WRITE : VM_READ;
-	if (!(vm_flags & vma->vm_flags))
+	if (!vma_permits_fault(vma, fault_flags))
 		return -EFAULT;
 
 	ret = handle_mm_fault(mm, vma, address, fault_flags);
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1234378 — [PATCH 08/25] x86, pkeys: store protection in high VMA flags

FromDave Hansen <dave@sr71.net>
Date2015-09-28 21:30 +0200
Subject[PATCH 08/25] x86, pkeys: store protection in high VMA flags
Message-ID<qdMhB-gH-47@gated-at.bofh.it>
In reply to#1234373
From: Dave Hansen <dave.hansen@linux.intel.com>

vma->vm_flags is an 'unsigned long', so has space for 32 flags
on 32-bit architectures.  The high 32 bits are unused on 64-bit
platforms.  We've steered away from using the unused high VMA
bits for things because we would have difficulty supporting it
on 32-bit.

Protection Keys are not available in 32-bit mode, so there is
no concern about supporting this feature in 32-bit mode or on
32-bit CPUs.

This patch carves out 4 bits from the high half of
vma->vm_flags and allows architectures to set config option
to make them available.

Sparse complains about these constants unless we explicitly
call them "UL".

Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---

 b/arch/x86/Kconfig   |    1 +
 b/include/linux/mm.h |    7 +++++++
 b/mm/Kconfig         |    3 +++
 3 files changed, 11 insertions(+)

diff -puN arch/x86/Kconfig~pkeys-07-eat-high-vma-flags arch/x86/Kconfig
--- a/arch/x86/Kconfig~pkeys-07-eat-high-vma-flags	2015-09-28 11:39:44.493116671 -0700
+++ b/arch/x86/Kconfig	2015-09-28 11:39:44.500116990 -0700
@@ -152,6 +152,7 @@ config X86
 	select VIRT_TO_BUS
 	select X86_DEV_DMA_OPS			if X86_64
 	select X86_FEATURE_NAMES		if PROC_FS
+	select ARCH_USES_HIGH_VMA_FLAGS		if X86_INTEL_MEMORY_PROTECTION_KEYS
 
 config INSTRUCTION_DECODER
 	def_bool y
diff -puN include/linux/mm.h~pkeys-07-eat-high-vma-flags include/linux/mm.h
--- a/include/linux/mm.h~pkeys-07-eat-high-vma-flags	2015-09-28 11:39:44.495116762 -0700
+++ b/include/linux/mm.h	2015-09-28 11:39:44.501117035 -0700
@@ -157,6 +157,13 @@ extern unsigned int kobjsize(const void
 #define VM_NOHUGEPAGE	0x40000000	/* MADV_NOHUGEPAGE marked this vma */
 #define VM_MERGEABLE	0x80000000	/* KSM may merge identical pages */
 
+#ifdef CONFIG_ARCH_USES_HIGH_VMA_FLAGS
+#define VM_HIGH_ARCH_0  0x100000000UL	/* bit only usable on 64-bit architectures */
+#define VM_HIGH_ARCH_1  0x200000000UL	/* bit only usable on 64-bit architectures */
+#define VM_HIGH_ARCH_2  0x400000000UL	/* bit only usable on 64-bit architectures */
+#define VM_HIGH_ARCH_3  0x800000000UL	/* bit only usable on 64-bit architectures */
+#endif /* CONFIG_ARCH_USES_HIGH_VMA_FLAGS */
+
 #if defined(CONFIG_X86)
 # define VM_PAT		VM_ARCH_1	/* PAT reserves whole VMA at once (x86) */
 #elif defined(CONFIG_PPC)
diff -puN mm/Kconfig~pkeys-07-eat-high-vma-flags mm/Kconfig
--- a/mm/Kconfig~pkeys-07-eat-high-vma-flags	2015-09-28 11:39:44.497116853 -0700
+++ b/mm/Kconfig	2015-09-28 11:39:44.502117081 -0700
@@ -680,3 +680,6 @@ config ZONE_DEVICE
 
 config FRAME_VECTOR
 	bool
+
+config ARCH_USES_HIGH_VMA_FLAGS
+	bool
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1234379 — [PATCH 06/25] x86, pkeys: PTE bits for storing protection key

FromDave Hansen <dave@sr71.net>
Date2015-09-28 21:30 +0200
Subject[PATCH 06/25] x86, pkeys: PTE bits for storing protection key
Message-ID<qdMhB-gH-57@gated-at.bofh.it>
In reply to#1234373
From: Dave Hansen <dave.hansen@linux.intel.com>

Previous documentation has referred to these 4 bits as "ignored".
That means that software could have made use of them.  But, as
far as I know, the kernel never used them.

They are still ignored when protection keys is not enabled, so
they could theoretically still get used for software purposes.

We also implement "empty" versions so that code that references
to them can be optimized away by the compiler when the config
option is not enabled.

Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---

 b/arch/x86/include/asm/pgtable_types.h |   17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff -puN arch/x86/include/asm/pgtable_types.h~pkeys-04-ptebits arch/x86/include/asm/pgtable_types.h
--- a/arch/x86/include/asm/pgtable_types.h~pkeys-04-ptebits	2015-09-28 11:39:43.661078823 -0700
+++ b/arch/x86/include/asm/pgtable_types.h	2015-09-28 11:39:43.665079005 -0700
@@ -25,7 +25,11 @@
 #define _PAGE_BIT_SPLITTING	_PAGE_BIT_SOFTW2 /* only valid on a PSE pmd */
 #define _PAGE_BIT_HIDDEN	_PAGE_BIT_SOFTW3 /* hidden by kmemcheck */
 #define _PAGE_BIT_SOFT_DIRTY	_PAGE_BIT_SOFTW3 /* software dirty tracking */
-#define _PAGE_BIT_NX           63       /* No execute: only valid after cpuid check */
+#define _PAGE_BIT_PKEY_BIT0	59       /* Protection Keys, bit 1/4 */
+#define _PAGE_BIT_PKEY_BIT1	60       /* Protection Keys, bit 2/4 */
+#define _PAGE_BIT_PKEY_BIT2	61       /* Protection Keys, bit 3/4 */
+#define _PAGE_BIT_PKEY_BIT3	62       /* Protection Keys, bit 4/4 */
+#define _PAGE_BIT_NX		63       /* No execute: only valid after cpuid check */
 
 /* If _PAGE_BIT_PRESENT is clear, we use these: */
 /* - if the user mapped it with PROT_NONE; pte_present gives true */
@@ -47,6 +51,17 @@
 #define _PAGE_SPECIAL	(_AT(pteval_t, 1) << _PAGE_BIT_SPECIAL)
 #define _PAGE_CPA_TEST	(_AT(pteval_t, 1) << _PAGE_BIT_CPA_TEST)
 #define _PAGE_SPLITTING	(_AT(pteval_t, 1) << _PAGE_BIT_SPLITTING)
+#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
+#define _PAGE_PKEY_BIT0	(_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT0)
+#define _PAGE_PKEY_BIT1	(_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT1)
+#define _PAGE_PKEY_BIT2	(_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT2)
+#define _PAGE_PKEY_BIT3	(_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT3)
+#else
+#define _PAGE_PKEY_BIT0	(_AT(pteval_t, 0))
+#define _PAGE_PKEY_BIT1	(_AT(pteval_t, 0))
+#define _PAGE_PKEY_BIT2	(_AT(pteval_t, 0))
+#define _PAGE_PKEY_BIT3	(_AT(pteval_t, 0))
+#endif
 #define __HAVE_ARCH_PTE_SPECIAL
 
 #ifdef CONFIG_KMEMCHECK
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1234380 — [PATCH 14/25] mm: simplify get_user_pages() PTE bit handling

FromDave Hansen <dave@sr71.net>
Date2015-09-28 21:30 +0200
Subject[PATCH 14/25] mm: simplify get_user_pages() PTE bit handling
Message-ID<qdMhB-gH-55@gated-at.bofh.it>
In reply to#1234373
From: Dave Hansen <dave.hansen@linux.intel.com>

The current get_user_pages() code is a wee bit more complicated
than it needs to be for pte bit checking.  Currently, it establishes
a mask of required pte _PAGE_* bits and ensures that the pte it
goes after has all those bits.

We need to use the bits for our _PAGE_PRESENT check since
pte_present() is also true for _PAGE_PROTNONE, and we have no
accessor for _PAGE_USER, so need it there as well.

But we might as well just use pte_write() since we have it and
let the compiler work its magic on optimizing it.

This also consolidates the three identical copies of this code.

Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---

 b/arch/x86/mm/gup.c |   34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff -puN arch/x86/mm/gup.c~pkeys-16-gup-swizzle arch/x86/mm/gup.c
--- a/arch/x86/mm/gup.c~pkeys-16-gup-swizzle	2015-09-28 11:39:47.203239951 -0700
+++ b/arch/x86/mm/gup.c	2015-09-28 11:39:47.206240088 -0700
@@ -63,6 +63,19 @@ retry:
 #endif
 }
 
+static inline int pte_allows_gup(pte_t pte, int write)
+{
+	/*
+	 * Note that pte_present() is true for !_PAGE_PRESENT
+	 * but _PAGE_PROTNONE, so we can not use it here.
+	 */
+	if (!(pte_flags(pte) & (_PAGE_PRESENT|_PAGE_USER)))
+		return 0;
+	if (write && !pte_write(pte))
+		return 0;
+	return 1;
+}
+
 /*
  * The performance critical leaf functions are made noinline otherwise gcc
  * inlines everything into a single function which results in too much
@@ -71,13 +84,8 @@ retry:
 static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
 		unsigned long end, int write, struct page **pages, int *nr)
 {
-	unsigned long mask;
 	pte_t *ptep;
 
-	mask = _PAGE_PRESENT|_PAGE_USER;
-	if (write)
-		mask |= _PAGE_RW;
-
 	ptep = pte_offset_map(&pmd, addr);
 	do {
 		pte_t pte = gup_get_pte(ptep);
@@ -88,8 +96,8 @@ static noinline int gup_pte_range(pmd_t
 			pte_unmap(ptep);
 			return 0;
 		}
-
-		if ((pte_flags(pte) & (mask | _PAGE_SPECIAL)) != mask) {
+		if (!pte_allows_gup(pte, write) ||
+		    pte_special(pte)) {
 			pte_unmap(ptep);
 			return 0;
 		}
@@ -117,15 +125,11 @@ static inline void get_head_page_multipl
 static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
 		unsigned long end, int write, struct page **pages, int *nr)
 {
-	unsigned long mask;
 	pte_t pte = *(pte_t *)&pmd;
 	struct page *head, *page;
 	int refs;
 
-	mask = _PAGE_PRESENT|_PAGE_USER;
-	if (write)
-		mask |= _PAGE_RW;
-	if ((pte_flags(pte) & mask) != mask)
+	if (!pte_allows_gup(pte, write))
 		return 0;
 	/* hugepages are never "special" */
 	VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL);
@@ -194,15 +198,11 @@ static int gup_pmd_range(pud_t pud, unsi
 static noinline int gup_huge_pud(pud_t pud, unsigned long addr,
 		unsigned long end, int write, struct page **pages, int *nr)
 {
-	unsigned long mask;
 	pte_t pte = *(pte_t *)&pud;
 	struct page *head, *page;
 	int refs;
 
-	mask = _PAGE_PRESENT|_PAGE_USER;
-	if (write)
-		mask |= _PAGE_RW;
-	if ((pte_flags(pte) & mask) != mask)
+	if (!pte_allows_gup(pte, write))
 		return 0;
 	/* hugepages are never "special" */
 	VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL);
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web