1*3c27b408SMichael Jeanson // SPDX-License-Identifier: MIT 2*3c27b408SMichael Jeanson // SPDX-FileCopyrightText: 2024 Michael Jeanson <mjeanson@efficios.com> 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 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 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