segv_errors.c 1.4 KB

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