hc
2024-08-16 a24a44ff9ca902811b99aa9663d697cf452e08ef
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;
}