Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1234373 > unrolled thread
| Started by | Dave Hansen <dave@sr71.net> |
|---|---|
| First post | 2015-09-28 21:30 +0200 |
| Last post | 2015-09-28 21:30 +0200 |
| Articles | 12 — 3 participants |
Back to article view | Back to linux.kernel
[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
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-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]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-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(¤t->mm->mmap_sem);
@@ -443,3 +445,15 @@ out:
up_write(¤t->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]
| From | Michael Ellerman <mpe@ellerman.id.au> |
|---|---|
| Date | 2015-09-29 08:40 +0200 |
| Subject | Re: [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]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-09-29 16:20 +0200 |
| Subject | Re: [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]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-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]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2015-10-01 14:00 +0200 |
| Subject | Re: [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]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-10-01 19:20 +0200 |
| Subject | Re: [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]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-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]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-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]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-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]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-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]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-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