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