All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] x86/mm/pkeys: fix user-visible pkey state destruction at fork()
@ 2019-01-02 21:56 Dave Hansen
  2019-01-02 21:56 ` [PATCH 1/2] x86/pkeys: properly copy pkey state " Dave Hansen
  2019-01-02 21:56 ` [PATCH 2/2] x86/selftests/pkeys: fork() to check for state being preserved Dave Hansen
  0 siblings, 2 replies; 8+ messages in thread
From: Dave Hansen @ 2019-01-02 21:56 UTC (permalink / raw)
  To: linux-kernel
  Cc: Dave Hansen, x86, tglx, mingo, bp, hpa, peterz, mpe, will.deacon,
	luto, jroedel, stable

Hi x86 maintainers,

This is an important fix that I believe needs to be merged for 4.21.
Without it, applications calling fork() can potentially double-allocate
a protection key, causing lots of strange problems.

Thomas's Reviewed-by is on the the actual fix, but not the selftest.

I would also be happy to send this as a pull request if you would
prefer.

Cc: x86@kernel.org
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Joerg Roedel <jroedel@suse.de>
Cc: stable@vger.kernel.org

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] x86/pkeys: properly copy pkey state at fork()
  2019-01-02 21:56 [PATCH 0/2] x86/mm/pkeys: fix user-visible pkey state destruction at fork() Dave Hansen
@ 2019-01-02 21:56 ` Dave Hansen
       [not found]   ` <20190103135224.1BC7A21479@mail.kernel.org>
  2019-01-15  9:36   ` [tip:x86/urgent] x86/pkeys: Properly " tip-bot for Dave Hansen
  2019-01-02 21:56 ` [PATCH 2/2] x86/selftests/pkeys: fork() to check for state being preserved Dave Hansen
  1 sibling, 2 replies; 8+ messages in thread
From: Dave Hansen @ 2019-01-02 21:56 UTC (permalink / raw)
  To: linux-kernel
  Cc: Dave Hansen, tglx, mingo, bp, hpa, x86, peterz, mpe, will.deacon,
	luto, jroedel, stable


From: Dave Hansen <dave.hansen@linux.intel.com>

Memory protection key behavior should be the same in a child as it was
in the parent before a fork.  But, there is a bug that resets the
state in the child at fork instead of preserving it.

Our creation of new mm's is a bit convoluted.  At fork(), the code
does:

	1. memcpy() the parent mm to initialize child
	2. mm_init() to initalize some select stuff stuff
	3. dup_mmap() to create true copies that memcpy()
	   did not do right.

For pkeys, we need to preserve two bits of state across a fork:
'execute_only_pkey' and 'pkey_allocation_map'.  Those are preserved by
the memcpy(), which I thought did the right thing.  But, mm_init()
calls init_new_context(), which I thought was *only* for execve()-time
and overwrites 'execute_only_pkey' and 'pkey_allocation_map' with
"new" values.  But, alas, init_new_context() is used at execve() and
fork().

The result is that, after a fork(), the child's pkey state ends up
looking like it does after an execve(), which is totally wrong.  pkeys
that are already allocated can be allocated again, for instance.

To fix this, add code called by dup_mmap() to copy the pkey state from
parent to child explicitly.  Also add a comment above init_new_context()
to make it more clear to the next poor sod what this code is used for.

Fixes: e8c24d3a23a ("x86/pkeys: Allocation/free syscalls")
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: x86@kernel.org
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Joerg Roedel <jroedel@suse.de>
Cc: stable@vger.kernel.org
---

 b/arch/x86/include/asm/mmu_context.h |   18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff -puN arch/x86/include/asm/mmu_context.h~x86-pkeys-no-init-at-fork arch/x86/include/asm/mmu_context.h
--- a/arch/x86/include/asm/mmu_context.h~x86-pkeys-no-init-at-fork	2019-01-02 13:53:53.217951966 -0800
+++ b/arch/x86/include/asm/mmu_context.h	2019-01-02 13:53:53.221951966 -0800
@@ -178,6 +178,10 @@ static inline void switch_ldt(struct mm_
 
 void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk);
 
+/*
+ * Init a new mm.  Used on mm copies, like at fork()
+ * and on mm's that are brand-new, like at execve().
+ */
 static inline int init_new_context(struct task_struct *tsk,
 				   struct mm_struct *mm)
 {
@@ -228,8 +232,22 @@ do {						\
 } while (0)
 #endif
 
+static inline void arch_dup_pkeys(struct mm_struct *oldmm,
+				  struct mm_struct *mm)
+{
+#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
+	if (!cpu_feature_enabled(X86_FEATURE_OSPKE))
+		return;
+
+	/* Duplicate the oldmm pkey state in mm: */
+	mm->context.pkey_allocation_map = oldmm->context.pkey_allocation_map;
+	mm->context.execute_only_pkey   = oldmm->context.execute_only_pkey;
+#endif
+}
+
 static inline int arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
 {
+	arch_dup_pkeys(oldmm, mm);
 	paravirt_arch_dup_mmap(oldmm, mm);
 	return ldt_dup_context(oldmm, mm);
 }
_

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 2/2] x86/selftests/pkeys: fork() to check for state being preserved
  2019-01-02 21:56 [PATCH 0/2] x86/mm/pkeys: fix user-visible pkey state destruction at fork() Dave Hansen
  2019-01-02 21:56 ` [PATCH 1/2] x86/pkeys: properly copy pkey state " Dave Hansen
@ 2019-01-02 21:56 ` Dave Hansen
       [not found]   ` <20190103135225.4929F217D9@mail.kernel.org>
  2019-01-15  9:37   ` [tip:x86/urgent] x86/selftests/pkeys: Fork() " tip-bot for Dave Hansen
  1 sibling, 2 replies; 8+ messages in thread
From: Dave Hansen @ 2019-01-02 21:56 UTC (permalink / raw)
  To: linux-kernel
  Cc: Dave Hansen, tglx, mingo, bp, hpa, x86, peterz, mpe, will.deacon,
	luto, jroedel, stable


From: Dave Hansen <dave.hansen@linux.intel.com>

There was a bug where the per-mm pkey state was not being preserved
across fork() in the child.  fork() is performed in the pkey
selftests, but all of our pkey activity is performed in the parent.
The child does not perform any actions sensitive to pkey state.

To make the test more sensitive to these kinds of bugs, add a
fork() where we let the parent exit, and continue execution in
the child.

This patch removes an early 'break;' on the first allocation failure,
making the test sensitive to mis-allowed allocations after fork().
However, this means that the loop always runs to completion and we
must remove the test ensuring the loop never completes.

Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: x86@kernel.org
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Joerg Roedel <jroedel@suse.de>
Cc: stable@vger.kernel.org
---

 b/tools/testing/selftests/x86/protection_keys.c |   41 ++++++++++++++++++------
 1 file changed, 31 insertions(+), 10 deletions(-)

diff -puN tools/testing/selftests/x86/protection_keys.c~x86-pkeys-no-init-at-fork-selftests tools/testing/selftests/x86/protection_keys.c
--- a/tools/testing/selftests/x86/protection_keys.c~x86-pkeys-no-init-at-fork-selftests	2019-01-02 13:53:53.721951964 -0800
+++ b/tools/testing/selftests/x86/protection_keys.c	2019-01-02 13:53:53.724951964 -0800
@@ -1133,6 +1133,21 @@ void test_pkey_syscalls_bad_args(int *pt
 	pkey_assert(err);
 }
 
+void become_child(void)
+{
+	pid_t forkret;
+
+	forkret = fork();
+	pkey_assert(forkret >= 0);
+	dprintf3("[%d] fork() ret: %d\n", getpid(), forkret);
+
+	if (!forkret) {
+		/* in the child */
+		return;
+	}
+	exit(0);
+}
+
 /* Assumes that all pkeys other than 'pkey' are unallocated */
 void test_pkey_alloc_exhaust(int *ptr, u16 pkey)
 {
@@ -1141,7 +1156,7 @@ void test_pkey_alloc_exhaust(int *ptr, u
 	int nr_allocated_pkeys = 0;
 	int i;
 
-	for (i = 0; i < NR_PKEYS*2; i++) {
+	for (i = 0; i < NR_PKEYS*3; i++) {
 		int new_pkey;
 		dprintf1("%s() alloc loop: %d\n", __func__, i);
 		new_pkey = alloc_pkey();
@@ -1152,21 +1167,27 @@ void test_pkey_alloc_exhaust(int *ptr, u
 		if ((new_pkey == -1) && (errno == ENOSPC)) {
 			dprintf2("%s() failed to allocate pkey after %d tries\n",
 				__func__, nr_allocated_pkeys);
-			break;
+		} else {
+			/*
+			 * Ensure the number of successes never
+			 * exceeds the number of keys supported
+			 * in the hardware.
+			 */
+			pkey_assert(nr_allocated_pkeys < NR_PKEYS);
+			allocated_pkeys[nr_allocated_pkeys++] = new_pkey;
 		}
-		pkey_assert(nr_allocated_pkeys < NR_PKEYS);
-		allocated_pkeys[nr_allocated_pkeys++] = new_pkey;
+
+		/*
+		 * Make sure that allocation state is properly
+		 * preserved across fork().
+		 */
+		if (i == NR_PKEYS*2)
+			become_child();
 	}
 
 	dprintf3("%s()::%d\n", __func__, __LINE__);
 
 	/*
-	 * ensure it did not reach the end of the loop without
-	 * failure:
-	 */
-	pkey_assert(i < NR_PKEYS*2);
-
-	/*
 	 * There are 16 pkeys supported in hardware.  Three are
 	 * allocated by the time we get here:
 	 *   1. The default key (0)
_

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] x86/pkeys: properly copy pkey state at fork()
       [not found]   ` <20190103135224.1BC7A21479@mail.kernel.org>
@ 2019-01-03 18:54     ` Dave Hansen
  0 siblings, 0 replies; 8+ messages in thread
From: Dave Hansen @ 2019-01-03 18:54 UTC (permalink / raw)
  To: Sasha Levin, Dave Hansen, linux-kernel
  Cc: tglx, Ingo Molnar, Borislav Petkov, H. Peter Anvin, x86,
	Peter Zijlstra, Michael Ellerman, Will Deacon, Andy Lutomirski,
	Joerg Roedel, stable

On 1/3/19 5:52 AM, Sasha Levin wrote:
> This commit has been processed because it contains a "Fixes:" tag,
> fixing commit: e8c24d3a23a4 x86/pkeys: Allocation/free syscalls.
> 
> The bot has tested the following trees: v4.20.0, v4.19.13, v4.14.91, v4.9.148, 
> 
> v4.20.0: Build OK!
> v4.19.13: Build OK!
> v4.14.91: Build OK!
> v4.9.148: Failed to apply! Possible dependencies:
>     c10e83f598d0 ("arch, mm: Allow arch_dup_mmap() to fail")
> 
> 
> How should we proceed with this patch?

The 4.9 version of arch_dup_mmap() does not contain the
ldt_dup_context() line.  We just need to add arch_dup_pkeys(), like so:

 void arch_dup_mmap(struct mm_struct *oldmm,
                                 struct mm_struct *mm)
 {
+       arch_dup_pkeys(oldmm, mm);
        paravirt_arch_dup_mmap(oldmm, mm);
 }

Should be a pretty simple merge.  We can basically ignore the
ldt_dup_context() changes.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] x86/selftests/pkeys: fork() to check for state being preserved
       [not found]   ` <20190103135225.4929F217D9@mail.kernel.org>
@ 2019-01-03 18:57     ` Dave Hansen
  2019-01-10 19:16       ` Greg KH
  0 siblings, 1 reply; 8+ messages in thread
From: Dave Hansen @ 2019-01-03 18:57 UTC (permalink / raw)
  To: Sasha Levin, Dave Hansen, linux-kernel
  Cc: tglx, Ingo Molnar, Borislav Petkov, H. Peter Anvin, x86,
	Peter Zijlstra, Michael Ellerman, Will Deacon, Andy Lutomirski,
	Joerg Roedel, stable, Shuah Khan

On 1/3/19 5:52 AM, Sasha Levin wrote:
> This commit has been processed because it contains a -stable tag.
> The stable tag indicates that it's relevant for the following trees: all
> 
> The bot has tested the following trees: v4.20.0, v4.19.13, v4.14.91, v4.9.148, v4.4.169, v3.18.131, 
> 
> v4.20.0: Build OK!
> v4.19.13: Build OK!
> v4.14.91: Build OK!
> v4.9.148: Failed to apply! Possible dependencies:
>     f50b4878329a ("x86/pkeys/selftests: Fix pkey exhaustion test off-by-one")

Protection keys was merged in 4.8.  We can ignore any of the selftests
changes before that.

But, it looks like the 4.9 selftests are a bit behind mainline.
Probably because I didn't cc stable@ on f50b4878329a.  I don't have a
strong opinion as to how up-to-date we want to keep the -stable
selftests.  Shua, is there a usual way that folks do this?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] x86/selftests/pkeys: fork() to check for state being preserved
  2019-01-03 18:57     ` Dave Hansen
@ 2019-01-10 19:16       ` Greg KH
  0 siblings, 0 replies; 8+ messages in thread
From: Greg KH @ 2019-01-10 19:16 UTC (permalink / raw)
  To: Dave Hansen
  Cc: Sasha Levin, Dave Hansen, linux-kernel, tglx, Ingo Molnar,
	Borislav Petkov, H. Peter Anvin, x86, Peter Zijlstra,
	Michael Ellerman, Will Deacon, Andy Lutomirski, Joerg Roedel,
	stable, Shuah Khan

On Thu, Jan 03, 2019 at 10:57:24AM -0800, Dave Hansen wrote:
> On 1/3/19 5:52 AM, Sasha Levin wrote:
> > This commit has been processed because it contains a -stable tag.
> > The stable tag indicates that it's relevant for the following trees: all
> > 
> > The bot has tested the following trees: v4.20.0, v4.19.13, v4.14.91, v4.9.148, v4.4.169, v3.18.131, 
> > 
> > v4.20.0: Build OK!
> > v4.19.13: Build OK!
> > v4.14.91: Build OK!
> > v4.9.148: Failed to apply! Possible dependencies:
> >     f50b4878329a ("x86/pkeys/selftests: Fix pkey exhaustion test off-by-one")
> 
> Protection keys was merged in 4.8.  We can ignore any of the selftests
> changes before that.
> 
> But, it looks like the 4.9 selftests are a bit behind mainline.
> Probably because I didn't cc stable@ on f50b4878329a.  I don't have a
> strong opinion as to how up-to-date we want to keep the -stable
> selftests.  Shua, is there a usual way that folks do this?

I wouldn't worry too much about selftests.  Usually people run the
latest selftests (like 4.20) on older stable kernels, as they "should"
just work properly (or at least fail gracefully).

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [tip:x86/urgent] x86/pkeys: Properly copy pkey state at fork()
  2019-01-02 21:56 ` [PATCH 1/2] x86/pkeys: properly copy pkey state " Dave Hansen
       [not found]   ` <20190103135224.1BC7A21479@mail.kernel.org>
@ 2019-01-15  9:36   ` tip-bot for Dave Hansen
  1 sibling, 0 replies; 8+ messages in thread
From: tip-bot for Dave Hansen @ 2019-01-15  9:36 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, tglx, mpe, will.deacon, mingo, luto, jroedel,
	dave.hansen, hpa, bp, peterz

Commit-ID:  a31e184e4f69965c99c04cc5eb8a4920e0c63737
Gitweb:     https://git.kernel.org/tip/a31e184e4f69965c99c04cc5eb8a4920e0c63737
Author:     Dave Hansen <dave.hansen@linux.intel.com>
AuthorDate: Wed, 2 Jan 2019 13:56:55 -0800
Committer:  Thomas Gleixner <tglx@linutronix.de>
CommitDate: Tue, 15 Jan 2019 10:33:45 +0100

x86/pkeys: Properly copy pkey state at fork()

Memory protection key behavior should be the same in a child as it was
in the parent before a fork.  But, there is a bug that resets the
state in the child at fork instead of preserving it.

The creation of new mm's is a bit convoluted.  At fork(), the code
does:

  1. memcpy() the parent mm to initialize child
  2. mm_init() to initalize some select stuff stuff
  3. dup_mmap() to create true copies that memcpy() did not do right

For pkeys two bits of state need to be preserved across a fork:
'execute_only_pkey' and 'pkey_allocation_map'.

Those are preserved by the memcpy(), but mm_init() invokes
init_new_context() which overwrites 'execute_only_pkey' and
'pkey_allocation_map' with "new" values.

The author of the code erroneously believed that init_new_context is *only*
called at execve()-time.  But, alas, init_new_context() is used at execve()
and fork().

The result is that, after a fork(), the child's pkey state ends up looking
like it does after an execve(), which is totally wrong.  pkeys that are
already allocated can be allocated again, for instance.

To fix this, add code called by dup_mmap() to copy the pkey state from
parent to child explicitly.  Also add a comment above init_new_context() to
make it more clear to the next poor sod what this code is used for.

Fixes: e8c24d3a23a ("x86/pkeys: Allocation/free syscalls")
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Cc: bp@alien8.de
Cc: hpa@zytor.com
Cc: peterz@infradead.org
Cc: mpe@ellerman.id.au
Cc: will.deacon@arm.com
Cc: luto@kernel.org
Cc: jroedel@suse.de
Cc: stable@vger.kernel.org
Cc: Borislav Petkov <bp@alien8.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Joerg Roedel <jroedel@suse.de>
Link: https://lkml.kernel.org/r/20190102215655.7A69518C@viggo.jf.intel.com

---
 arch/x86/include/asm/mmu_context.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index 0ca50611e8ce..19d18fae6ec6 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -178,6 +178,10 @@ static inline void switch_ldt(struct mm_struct *prev, struct mm_struct *next)
 
 void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk);
 
+/*
+ * Init a new mm.  Used on mm copies, like at fork()
+ * and on mm's that are brand-new, like at execve().
+ */
 static inline int init_new_context(struct task_struct *tsk,
 				   struct mm_struct *mm)
 {
@@ -228,8 +232,22 @@ do {						\
 } while (0)
 #endif
 
+static inline void arch_dup_pkeys(struct mm_struct *oldmm,
+				  struct mm_struct *mm)
+{
+#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
+	if (!cpu_feature_enabled(X86_FEATURE_OSPKE))
+		return;
+
+	/* Duplicate the oldmm pkey state in mm: */
+	mm->context.pkey_allocation_map = oldmm->context.pkey_allocation_map;
+	mm->context.execute_only_pkey   = oldmm->context.execute_only_pkey;
+#endif
+}
+
 static inline int arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
 {
+	arch_dup_pkeys(oldmm, mm);
 	paravirt_arch_dup_mmap(oldmm, mm);
 	return ldt_dup_context(oldmm, mm);
 }

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [tip:x86/urgent] x86/selftests/pkeys: Fork() to check for state being preserved
  2019-01-02 21:56 ` [PATCH 2/2] x86/selftests/pkeys: fork() to check for state being preserved Dave Hansen
       [not found]   ` <20190103135225.4929F217D9@mail.kernel.org>
@ 2019-01-15  9:37   ` tip-bot for Dave Hansen
  1 sibling, 0 replies; 8+ messages in thread
From: tip-bot for Dave Hansen @ 2019-01-15  9:37 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: mpe, will.deacon, linux-kernel, hpa, bp, mingo, luto, peterz,
	jroedel, dave.hansen, tglx

Commit-ID:  e1812933b17be7814f51b6c310c5d1ced7a9a5f5
Gitweb:     https://git.kernel.org/tip/e1812933b17be7814f51b6c310c5d1ced7a9a5f5
Author:     Dave Hansen <dave.hansen@linux.intel.com>
AuthorDate: Wed, 2 Jan 2019 13:56:57 -0800
Committer:  Thomas Gleixner <tglx@linutronix.de>
CommitDate: Tue, 15 Jan 2019 10:33:45 +0100

x86/selftests/pkeys: Fork() to check for state being preserved

There was a bug where the per-mm pkey state was not being preserved across
fork() in the child.  fork() is performed in the pkey selftests, but all of
the pkey activity is performed in the parent.  The child does not perform
any actions sensitive to pkey state.

To make the test more sensitive to these kinds of bugs, add a fork() where
the parent exits, and execution continues in the child.

To achieve this let the key exhaustion test not terminate at the first
allocation failure and fork after 2*NR_PKEYS loops and continue in the
child.

Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: bp@alien8.de
Cc: hpa@zytor.com
Cc: peterz@infradead.org
Cc: mpe@ellerman.id.au
Cc: will.deacon@arm.com
Cc: luto@kernel.org
Cc: jroedel@suse.de
Cc: stable@vger.kernel.org
Cc: Borislav Petkov <bp@alien8.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Joerg Roedel <jroedel@suse.de>
Link: https://lkml.kernel.org/r/20190102215657.585704B7@viggo.jf.intel.com

---
 tools/testing/selftests/x86/protection_keys.c | 41 ++++++++++++++++++++-------
 1 file changed, 31 insertions(+), 10 deletions(-)

diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c
index 460b4bdf4c1e..5d546dcdbc80 100644
--- a/tools/testing/selftests/x86/protection_keys.c
+++ b/tools/testing/selftests/x86/protection_keys.c
@@ -1133,6 +1133,21 @@ void test_pkey_syscalls_bad_args(int *ptr, u16 pkey)
 	pkey_assert(err);
 }
 
+void become_child(void)
+{
+	pid_t forkret;
+
+	forkret = fork();
+	pkey_assert(forkret >= 0);
+	dprintf3("[%d] fork() ret: %d\n", getpid(), forkret);
+
+	if (!forkret) {
+		/* in the child */
+		return;
+	}
+	exit(0);
+}
+
 /* Assumes that all pkeys other than 'pkey' are unallocated */
 void test_pkey_alloc_exhaust(int *ptr, u16 pkey)
 {
@@ -1141,7 +1156,7 @@ void test_pkey_alloc_exhaust(int *ptr, u16 pkey)
 	int nr_allocated_pkeys = 0;
 	int i;
 
-	for (i = 0; i < NR_PKEYS*2; i++) {
+	for (i = 0; i < NR_PKEYS*3; i++) {
 		int new_pkey;
 		dprintf1("%s() alloc loop: %d\n", __func__, i);
 		new_pkey = alloc_pkey();
@@ -1152,20 +1167,26 @@ void test_pkey_alloc_exhaust(int *ptr, u16 pkey)
 		if ((new_pkey == -1) && (errno == ENOSPC)) {
 			dprintf2("%s() failed to allocate pkey after %d tries\n",
 				__func__, nr_allocated_pkeys);
-			break;
+		} else {
+			/*
+			 * Ensure the number of successes never
+			 * exceeds the number of keys supported
+			 * in the hardware.
+			 */
+			pkey_assert(nr_allocated_pkeys < NR_PKEYS);
+			allocated_pkeys[nr_allocated_pkeys++] = new_pkey;
 		}
-		pkey_assert(nr_allocated_pkeys < NR_PKEYS);
-		allocated_pkeys[nr_allocated_pkeys++] = new_pkey;
+
+		/*
+		 * Make sure that allocation state is properly
+		 * preserved across fork().
+		 */
+		if (i == NR_PKEYS*2)
+			become_child();
 	}
 
 	dprintf3("%s()::%d\n", __func__, __LINE__);
 
-	/*
-	 * ensure it did not reach the end of the loop without
-	 * failure:
-	 */
-	pkey_assert(i < NR_PKEYS*2);
-
 	/*
 	 * There are 16 pkeys supported in hardware.  Three are
 	 * allocated by the time we get here:

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2019-01-15  9:37 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-02 21:56 [PATCH 0/2] x86/mm/pkeys: fix user-visible pkey state destruction at fork() Dave Hansen
2019-01-02 21:56 ` [PATCH 1/2] x86/pkeys: properly copy pkey state " Dave Hansen
     [not found]   ` <20190103135224.1BC7A21479@mail.kernel.org>
2019-01-03 18:54     ` Dave Hansen
2019-01-15  9:36   ` [tip:x86/urgent] x86/pkeys: Properly " tip-bot for Dave Hansen
2019-01-02 21:56 ` [PATCH 2/2] x86/selftests/pkeys: fork() to check for state being preserved Dave Hansen
     [not found]   ` <20190103135225.4929F217D9@mail.kernel.org>
2019-01-03 18:57     ` Dave Hansen
2019-01-10 19:16       ` Greg KH
2019-01-15  9:37   ` [tip:x86/urgent] x86/selftests/pkeys: Fork() " tip-bot for Dave Hansen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.