Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/powerpc: Add a test of SEGV error behaviour

Add a test case of the error code reported when we take a SEGV on a
mapped but inaccessible area. We broke this recently.

Based on a test case from John Sperbeck <jsperbeck@google.com>.

Acked-by: John Sperbeck <jsperbeck@google.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

+80 -1
+1
tools/testing/selftests/powerpc/mm/.gitignore
··· 2 2 subpage_prot 3 3 tempfile 4 4 prot_sao 5 + segv_errors
+1 -1
tools/testing/selftests/powerpc/mm/Makefile
··· 2 2 noarg: 3 3 $(MAKE) -C ../ 4 4 5 - TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot prot_sao 5 + TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot prot_sao segv_errors 6 6 TEST_GEN_FILES := tempfile 7 7 8 8 include ../../lib.mk
+78
tools/testing/selftests/powerpc/mm/segv_errors.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /* 4 + * Copyright 2017 John Sperbeck 5 + * 6 + * Test that an access to a mapped but inaccessible area causes a SEGV and 7 + * reports si_code == SEGV_ACCERR. 8 + */ 9 + 10 + #include <stdbool.h> 11 + #include <stdio.h> 12 + #include <stdlib.h> 13 + #include <string.h> 14 + #include <unistd.h> 15 + #include <signal.h> 16 + #include <sys/mman.h> 17 + #include <assert.h> 18 + #include <ucontext.h> 19 + 20 + #include "utils.h" 21 + 22 + static bool faulted; 23 + static int si_code; 24 + 25 + static void segv_handler(int n, siginfo_t *info, void *ctxt_v) 26 + { 27 + ucontext_t *ctxt = (ucontext_t *)ctxt_v; 28 + struct pt_regs *regs = ctxt->uc_mcontext.regs; 29 + 30 + faulted = true; 31 + si_code = info->si_code; 32 + regs->nip += 4; 33 + } 34 + 35 + int test_segv_errors(void) 36 + { 37 + struct sigaction act = { 38 + .sa_sigaction = segv_handler, 39 + .sa_flags = SA_SIGINFO, 40 + }; 41 + char c, *p = NULL; 42 + 43 + p = mmap(NULL, getpagesize(), 0, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 44 + FAIL_IF(p == MAP_FAILED); 45 + 46 + FAIL_IF(sigaction(SIGSEGV, &act, NULL) != 0); 47 + 48 + faulted = false; 49 + si_code = 0; 50 + 51 + /* 52 + * We just need a compiler barrier, but mb() works and has the nice 53 + * property of being easy to spot in the disassembly. 54 + */ 55 + mb(); 56 + c = *p; 57 + mb(); 58 + 59 + FAIL_IF(!faulted); 60 + FAIL_IF(si_code != SEGV_ACCERR); 61 + 62 + faulted = false; 63 + si_code = 0; 64 + 65 + mb(); 66 + *p = c; 67 + mb(); 68 + 69 + FAIL_IF(!faulted); 70 + FAIL_IF(si_code != SEGV_ACCERR); 71 + 72 + return 0; 73 + } 74 + 75 + int main(void) 76 + { 77 + return test_harness(test_segv_errors, "segv_errors"); 78 + }