| From e1812933b17be7814f51b6c310c5d1ced7a9a5f5 Mon Sep 17 00:00:00 2001 |
| From: Dave Hansen <dave.hansen@linux.intel.com> |
| Date: Wed, 2 Jan 2019 13:56:57 -0800 |
| Subject: x86/selftests/pkeys: Fork() to check for state being preserved |
| |
| From: Dave Hansen <dave.hansen@linux.intel.com> |
| |
| commit e1812933b17be7814f51b6c310c5d1ced7a9a5f5 upstream. |
| |
| 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 |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| tools/testing/selftests/x86/protection_keys.c | 41 +++++++++++++++++++------- |
| 1 file changed, 31 insertions(+), 10 deletions(-) |
| |
| --- 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 *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) |