File Index
Files and directories
Sign in
FILE

syscall_errors_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/rseq/syscall_errors_test.c C
  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
 16static 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
 26int 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;
122error:
123	return -1;
124}
~/ Read-only file preview.