syscall_errors_test.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // SPDX-License-Identifier: MIT
  2. // SPDX-FileCopyrightText: 2024 Michael Jeanson <mjeanson@efficios.com>
  3. #ifndef _GNU_SOURCE
  4. #define _GNU_SOURCE
  5. #endif
  6. #include <assert.h>
  7. #include <stdint.h>
  8. #include <syscall.h>
  9. #include <string.h>
  10. #include <unistd.h>
  11. #include "rseq.h"
  12. static int sys_rseq(void *rseq_abi, uint32_t rseq_len,
  13. int flags, uint32_t sig)
  14. {
  15. return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig);
  16. }
  17. /*
  18. * Check the value of errno on some expected failures of the rseq syscall.
  19. */
  20. int main(void)
  21. {
  22. struct rseq_abi *global_rseq = rseq_get_abi();
  23. int ret;
  24. int errno_copy;
  25. if (!rseq_available()) {
  26. fprintf(stderr, "rseq syscall unavailable");
  27. goto error;
  28. }
  29. /* The current thread is NOT registered. */
  30. /* EINVAL */
  31. errno = 0;
  32. ret = sys_rseq(global_rseq, 32, -1, RSEQ_SIG);
  33. errno_copy = errno;
  34. fprintf(stderr, "Registration with invalid flag fails with errno set to EINVAL (ret = %d, errno = %s)\n", ret, strerrorname_np(errno_copy));
  35. if (ret == 0 || errno_copy != EINVAL)
  36. goto error;
  37. errno = 0;
  38. ret = sys_rseq((char *) global_rseq + 1, 32, 0, RSEQ_SIG);
  39. errno_copy = errno;
  40. fprintf(stderr, "Registration with unaligned rseq_abi fails with errno set to EINVAL (ret = %d, errno = %s)\n", ret, strerrorname_np(errno_copy));
  41. if (ret == 0 || errno_copy != EINVAL)
  42. goto error;
  43. errno = 0;
  44. ret = sys_rseq(global_rseq, 31, 0, RSEQ_SIG);
  45. errno_copy = errno;
  46. fprintf(stderr, "Registration with invalid size fails with errno set to EINVAL (ret = %d, errno = %s)\n", ret, strerrorname_np(errno_copy));
  47. if (ret == 0 || errno_copy != EINVAL)
  48. goto error;
  49. #if defined(__LP64__) && (!defined(__s390__) && !defined(__s390x__))
  50. /*
  51. * We haven't found a reliable way to find an invalid address when
  52. * running a 32bit userspace on a 64bit kernel, so only run this test
  53. * on 64bit builds for the moment.
  54. *
  55. * Also exclude architectures that select
  56. * CONFIG_ALTERNATE_USER_ADDRESS_SPACE where the kernel and userspace
  57. * have their own address space and this failure can't happen.
  58. */
  59. /* EFAULT */
  60. errno = 0;
  61. ret = sys_rseq((void *) -4096UL, 32, 0, RSEQ_SIG);
  62. errno_copy = errno;
  63. fprintf(stderr, "Registration with invalid address fails with errno set to EFAULT (ret = %d, errno = %s)\n", ret, strerrorname_np(errno_copy));
  64. if (ret == 0 || errno_copy != EFAULT)
  65. goto error;
  66. #endif
  67. errno = 0;
  68. ret = sys_rseq(global_rseq, 32, 0, RSEQ_SIG);
  69. errno_copy = errno;
  70. fprintf(stderr, "Registration succeeds for the current thread (ret = %d, errno = %s)\n", ret, strerrorname_np(errno_copy));
  71. if (ret != 0 && errno != 0)
  72. goto error;
  73. /* The current thread is registered. */
  74. /* EBUSY */
  75. errno = 0;
  76. ret = sys_rseq(global_rseq, 32, 0, RSEQ_SIG);
  77. errno_copy = errno;
  78. fprintf(stderr, "Double registration fails with errno set to EBUSY (ret = %d, errno = %s)\n", ret, strerrorname_np(errno_copy));
  79. if (ret == 0 || errno_copy != EBUSY)
  80. goto error;
  81. /* EPERM */
  82. errno = 0;
  83. ret = sys_rseq(global_rseq, 32, RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG + 1);
  84. errno_copy = errno;
  85. fprintf(stderr, "Unregistration with wrong RSEQ_SIG fails with errno to EPERM (ret = %d, errno = %s)\n", ret, strerrorname_np(errno_copy));
  86. if (ret == 0 || errno_copy != EPERM)
  87. goto error;
  88. errno = 0;
  89. ret = sys_rseq(global_rseq, 32, RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG);
  90. errno_copy = errno;
  91. fprintf(stderr, "Unregistration succeeds for the current thread (ret = %d, errno = %s)\n", ret, strerrorname_np(errno_copy));
  92. if (ret != 0)
  93. goto error;
  94. errno = 0;
  95. ret = sys_rseq(global_rseq, 32, RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG);
  96. errno_copy = errno;
  97. fprintf(stderr, "Double unregistration fails with errno set to EINVAL (ret = %d, errno = %s)\n", ret, strerrorname_np(errno_copy));
  98. if (ret == 0 || errno_copy != EINVAL)
  99. goto error;
  100. return 0;
  101. error:
  102. return -1;
  103. }