summaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/x86/syscall_numbering.c
blob: d6b09cb1aa2c1e542de40c57328a13eb9bef0139 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * syscall_arg_fault.c - tests faults 32-bit fast syscall stack args
 * Copyright (c) 2018 Andrew Lutomirski
 */

#define _GNU_SOURCE

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <unistd.h>
#include <syscall.h>

static int nerrs;

#define X32_BIT 0x40000000UL

static void check_enosys(unsigned long nr, bool *ok)
{
	/* If this fails, a segfault is reasonably likely. */
	fflush(stdout);

	long ret = syscall(nr, 0, 0, 0, 0, 0, 0);
	if (ret == 0) {
		printf("[FAIL]\tsyscall %lu succeeded, but it should have failed\n", nr);
		*ok = false;
	} else if (errno != ENOSYS) {
		printf("[FAIL]\tsyscall %lu had error code %d, but it should have reported ENOSYS\n", nr, errno);
		*ok = false;
	}
}

static void test_x32_without_x32_bit(void)
{
	bool ok = true;

	/*
	 * Syscalls 512-547 are "x32" syscalls.  They are intended to be
	 * called with the x32 (0x40000000) bit set.  Calling them without
	 * the x32 bit set is nonsense and should not work.
	 */
	printf("[RUN]\tChecking syscalls 512-547\n");
	for (int i = 512; i <= 547; i++)
		check_enosys(i, &ok);

	/*
	 * Check that a handful of 64-bit-only syscalls are rejected if the x32
	 * bit is set.
	 */
	printf("[RUN]\tChecking some 64-bit syscalls in x32 range\n");
	check_enosys(16 | X32_BIT, &ok);	/* ioctl */
	check_enosys(19 | X32_BIT, &ok);	/* readv */
	check_enosys(20 | X32_BIT, &ok);	/* writev */

	/*
	 * Check some syscalls with high bits set.
	 */
	printf("[RUN]\tChecking numbers above 2^32-1\n");
	check_enosys((1UL << 32), &ok);
	check_enosys(X32_BIT | (1UL << 32), &ok);

	if (!ok)
		nerrs++;
	else
		printf("[OK]\tThey all returned -ENOSYS\n");
}

int main()
{
	/*
	 * Anyone diagnosing a failure will want to know whether the kernel
	 * supports x32.  Tell them.
	 */
	printf("\tChecking for x32...");
	fflush(stdout);
	if (syscall(39 | X32_BIT, 0, 0, 0, 0, 0, 0) >= 0) {
		printf(" supported\n");
	} else if (errno == ENOSYS) {
		printf(" not supported\n");
	} else {
		printf(" confused\n");
	}

	test_x32_without_x32_bit();

	return nerrs ? 1 : 0;
}