1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * syscall_arg_fault.c - tests faults 32-bit fast syscall stack args 4 * Copyright (c) 2018 Andrew Lutomirski 5 */ 6 7 #define _GNU_SOURCE 8 9 #include <stdlib.h> 10 #include <stdio.h> 11 #include <stdbool.h> 12 #include <errno.h> 13 #include <unistd.h> 14 #include <syscall.h> 15 16 static int nerrs; 17 18 #define X32_BIT 0x40000000UL 19 20 static void check_enosys(unsigned long nr, bool *ok) 21 { 22 /* If this fails, a segfault is reasonably likely. */ 23 fflush(stdout); 24 25 long ret = syscall(nr, 0, 0, 0, 0, 0, 0); 26 if (ret == 0) { 27 printf("[FAIL]\tsyscall %lu succeeded, but it should have failed\n", nr); 28 *ok = false; 29 } else if (errno != ENOSYS) { 30 printf("[FAIL]\tsyscall %lu had error code %d, but it should have reported ENOSYS\n", nr, errno); 31 *ok = false; 32 } 33 } 34 35 static void test_x32_without_x32_bit(void) 36 { 37 bool ok = true; 38 39 /* 40 * Syscalls 512-547 are "x32" syscalls. They are intended to be 41 * called with the x32 (0x40000000) bit set. Calling them without 42 * the x32 bit set is nonsense and should not work. 43 */ 44 printf("[RUN]\tChecking syscalls 512-547\n"); 45 for (int i = 512; i <= 547; i++) 46 check_enosys(i, &ok); 47 48 /* 49 * Check that a handful of 64-bit-only syscalls are rejected if the x32 50 * bit is set. 51 */ 52 printf("[RUN]\tChecking some 64-bit syscalls in x32 range\n"); 53 check_enosys(16 | X32_BIT, &ok); /* ioctl */ 54 check_enosys(19 | X32_BIT, &ok); /* readv */ 55 check_enosys(20 | X32_BIT, &ok); /* writev */ 56 57 /* 58 * Check some syscalls with high bits set. 59 */ 60 printf("[RUN]\tChecking numbers above 2^32-1\n"); 61 check_enosys((1UL << 32), &ok); 62 check_enosys(X32_BIT | (1UL << 32), &ok); 63 64 if (!ok) 65 nerrs++; 66 else 67 printf("[OK]\tThey all returned -ENOSYS\n"); 68 } 69 70 int main() 71 { 72 /* 73 * Anyone diagnosing a failure will want to know whether the kernel 74 * supports x32. Tell them. 75 */ 76 printf("\tChecking for x32..."); 77 fflush(stdout); 78 if (syscall(39 | X32_BIT, 0, 0, 0, 0, 0, 0) >= 0) { 79 printf(" supported\n"); 80 } else if (errno == ENOSYS) { 81 printf(" not supported\n"); 82 } else { 83 printf(" confused\n"); 84 } 85 86 test_x32_without_x32_bit(); 87 88 return nerrs ? 1 : 0; 89 } 90