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