162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * syscall_numbering.c - test calling the x86-64 kernel with various 462306a36Sopenharmony_ci * valid and invalid system call numbers. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 2018 Andrew Lutomirski 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define _GNU_SOURCE 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <stdlib.h> 1262306a36Sopenharmony_ci#include <stdio.h> 1362306a36Sopenharmony_ci#include <stdbool.h> 1462306a36Sopenharmony_ci#include <errno.h> 1562306a36Sopenharmony_ci#include <unistd.h> 1662306a36Sopenharmony_ci#include <string.h> 1762306a36Sopenharmony_ci#include <fcntl.h> 1862306a36Sopenharmony_ci#include <limits.h> 1962306a36Sopenharmony_ci#include <signal.h> 2062306a36Sopenharmony_ci#include <sysexits.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <sys/ptrace.h> 2362306a36Sopenharmony_ci#include <sys/user.h> 2462306a36Sopenharmony_ci#include <sys/wait.h> 2562306a36Sopenharmony_ci#include <sys/mman.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <linux/ptrace.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* Common system call numbers */ 3062306a36Sopenharmony_ci#define SYS_READ 0 3162306a36Sopenharmony_ci#define SYS_WRITE 1 3262306a36Sopenharmony_ci#define SYS_GETPID 39 3362306a36Sopenharmony_ci/* x64-only system call numbers */ 3462306a36Sopenharmony_ci#define X64_IOCTL 16 3562306a36Sopenharmony_ci#define X64_READV 19 3662306a36Sopenharmony_ci#define X64_WRITEV 20 3762306a36Sopenharmony_ci/* x32-only system call numbers (without X32_BIT) */ 3862306a36Sopenharmony_ci#define X32_IOCTL 514 3962306a36Sopenharmony_ci#define X32_READV 515 4062306a36Sopenharmony_ci#define X32_WRITEV 516 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define X32_BIT 0x40000000 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic int nullfd = -1; /* File descriptor for /dev/null */ 4562306a36Sopenharmony_cistatic bool with_x32; /* x32 supported on this kernel? */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cienum ptrace_pass { 4862306a36Sopenharmony_ci PTP_NOTHING, 4962306a36Sopenharmony_ci PTP_GETREGS, 5062306a36Sopenharmony_ci PTP_WRITEBACK, 5162306a36Sopenharmony_ci PTP_FUZZRET, 5262306a36Sopenharmony_ci PTP_FUZZHIGH, 5362306a36Sopenharmony_ci PTP_INTNUM, 5462306a36Sopenharmony_ci PTP_DONE 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic const char * const ptrace_pass_name[] = 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci [PTP_NOTHING] = "just stop, no data read", 6062306a36Sopenharmony_ci [PTP_GETREGS] = "only getregs", 6162306a36Sopenharmony_ci [PTP_WRITEBACK] = "getregs, unmodified setregs", 6262306a36Sopenharmony_ci [PTP_FUZZRET] = "modifying the default return", 6362306a36Sopenharmony_ci [PTP_FUZZHIGH] = "clobbering the top 32 bits", 6462306a36Sopenharmony_ci [PTP_INTNUM] = "sign-extending the syscall number", 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* 6862306a36Sopenharmony_ci * Shared memory block between tracer and test 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_cistruct shared { 7162306a36Sopenharmony_ci unsigned int nerr; /* Total error count */ 7262306a36Sopenharmony_ci unsigned int indent; /* Message indentation level */ 7362306a36Sopenharmony_ci enum ptrace_pass ptrace_pass; 7462306a36Sopenharmony_ci bool probing_syscall; /* In probe_syscall() */ 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_cistatic volatile struct shared *sh; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic inline unsigned int offset(void) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci unsigned int level = sh ? sh->indent : 0; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return 8 + level * 4; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define msg(lvl, fmt, ...) printf("%-*s" fmt, offset(), "[" #lvl "]", \ 8662306a36Sopenharmony_ci ## __VA_ARGS__) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define run(fmt, ...) msg(RUN, fmt, ## __VA_ARGS__) 8962306a36Sopenharmony_ci#define info(fmt, ...) msg(INFO, fmt, ## __VA_ARGS__) 9062306a36Sopenharmony_ci#define ok(fmt, ...) msg(OK, fmt, ## __VA_ARGS__) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define fail(fmt, ...) \ 9362306a36Sopenharmony_ci do { \ 9462306a36Sopenharmony_ci msg(FAIL, fmt, ## __VA_ARGS__); \ 9562306a36Sopenharmony_ci sh->nerr++; \ 9662306a36Sopenharmony_ci } while (0) 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#define crit(fmt, ...) \ 9962306a36Sopenharmony_ci do { \ 10062306a36Sopenharmony_ci sh->indent = 0; \ 10162306a36Sopenharmony_ci msg(FAIL, fmt, ## __VA_ARGS__); \ 10262306a36Sopenharmony_ci msg(SKIP, "Unable to run test\n"); \ 10362306a36Sopenharmony_ci exit(EX_OSERR); \ 10462306a36Sopenharmony_ci } while (0) 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* Sentinel for ptrace-modified return value */ 10762306a36Sopenharmony_ci#define MODIFIED_BY_PTRACE -9999 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* 11062306a36Sopenharmony_ci * Directly invokes the given syscall with nullfd as the first argument 11162306a36Sopenharmony_ci * and the rest zero. Avoids involving glibc wrappers in case they ever 11262306a36Sopenharmony_ci * end up intercepting some system calls for some reason, or modify 11362306a36Sopenharmony_ci * the system call number itself. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_cistatic long long probe_syscall(int msb, int lsb) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci register long long arg1 asm("rdi") = nullfd; 11862306a36Sopenharmony_ci register long long arg2 asm("rsi") = 0; 11962306a36Sopenharmony_ci register long long arg3 asm("rdx") = 0; 12062306a36Sopenharmony_ci register long long arg4 asm("r10") = 0; 12162306a36Sopenharmony_ci register long long arg5 asm("r8") = 0; 12262306a36Sopenharmony_ci register long long arg6 asm("r9") = 0; 12362306a36Sopenharmony_ci long long nr = ((long long)msb << 32) | (unsigned int)lsb; 12462306a36Sopenharmony_ci long long ret; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* 12762306a36Sopenharmony_ci * We pass in an extra copy of the extended system call number 12862306a36Sopenharmony_ci * in %rbx, so we can examine it from the ptrace handler without 12962306a36Sopenharmony_ci * worrying about it being possibly modified. This is to test 13062306a36Sopenharmony_ci * the validity of struct user regs.orig_rax a.k.a. 13162306a36Sopenharmony_ci * struct pt_regs.orig_ax. 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci sh->probing_syscall = true; 13462306a36Sopenharmony_ci asm volatile("syscall" 13562306a36Sopenharmony_ci : "=a" (ret) 13662306a36Sopenharmony_ci : "a" (nr), "b" (nr), 13762306a36Sopenharmony_ci "r" (arg1), "r" (arg2), "r" (arg3), 13862306a36Sopenharmony_ci "r" (arg4), "r" (arg5), "r" (arg6) 13962306a36Sopenharmony_ci : "rcx", "r11", "memory", "cc"); 14062306a36Sopenharmony_ci sh->probing_syscall = false; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return ret; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic const char *syscall_str(int msb, int start, int end) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci static char buf[64]; 14862306a36Sopenharmony_ci const char * const type = (start & X32_BIT) ? "x32" : "x64"; 14962306a36Sopenharmony_ci int lsb = start; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* 15262306a36Sopenharmony_ci * Improve readability by stripping the x32 bit, but round 15362306a36Sopenharmony_ci * toward zero so we don't display -1 as -1073741825. 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_ci if (lsb < 0) 15662306a36Sopenharmony_ci lsb |= X32_BIT; 15762306a36Sopenharmony_ci else 15862306a36Sopenharmony_ci lsb &= ~X32_BIT; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (start == end) 16162306a36Sopenharmony_ci snprintf(buf, sizeof buf, "%s syscall %d:%d", 16262306a36Sopenharmony_ci type, msb, lsb); 16362306a36Sopenharmony_ci else 16462306a36Sopenharmony_ci snprintf(buf, sizeof buf, "%s syscalls %d:%d..%d", 16562306a36Sopenharmony_ci type, msb, lsb, lsb + (end-start)); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return buf; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic unsigned int _check_for(int msb, int start, int end, long long expect, 17162306a36Sopenharmony_ci const char *expect_str) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci unsigned int err = 0; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci sh->indent++; 17662306a36Sopenharmony_ci if (start != end) 17762306a36Sopenharmony_ci sh->indent++; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci for (int nr = start; nr <= end; nr++) { 18062306a36Sopenharmony_ci long long ret = probe_syscall(msb, nr); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (ret != expect) { 18362306a36Sopenharmony_ci fail("%s returned %lld, but it should have returned %s\n", 18462306a36Sopenharmony_ci syscall_str(msb, nr, nr), 18562306a36Sopenharmony_ci ret, expect_str); 18662306a36Sopenharmony_ci err++; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (start != end) 19162306a36Sopenharmony_ci sh->indent--; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (err) { 19462306a36Sopenharmony_ci if (start != end) 19562306a36Sopenharmony_ci fail("%s had %u failure%s\n", 19662306a36Sopenharmony_ci syscall_str(msb, start, end), 19762306a36Sopenharmony_ci err, err == 1 ? "s" : ""); 19862306a36Sopenharmony_ci } else { 19962306a36Sopenharmony_ci ok("%s returned %s as expected\n", 20062306a36Sopenharmony_ci syscall_str(msb, start, end), expect_str); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci sh->indent--; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return err; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci#define check_for(msb,start,end,expect) \ 20962306a36Sopenharmony_ci _check_for(msb,start,end,expect,#expect) 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic bool check_zero(int msb, int nr) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci return check_for(msb, nr, nr, 0); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic bool check_enosys(int msb, int nr) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci return check_for(msb, nr, nr, -ENOSYS); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/* 22262306a36Sopenharmony_ci * Anyone diagnosing a failure will want to know whether the kernel 22362306a36Sopenharmony_ci * supports x32. Tell them. This can also be used to conditionalize 22462306a36Sopenharmony_ci * tests based on existence or nonexistence of x32. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_cistatic bool test_x32(void) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci long long ret; 22962306a36Sopenharmony_ci pid_t mypid = getpid(); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci run("Checking for x32 by calling x32 getpid()\n"); 23262306a36Sopenharmony_ci ret = probe_syscall(0, SYS_GETPID | X32_BIT); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci sh->indent++; 23562306a36Sopenharmony_ci if (ret == mypid) { 23662306a36Sopenharmony_ci info("x32 is supported\n"); 23762306a36Sopenharmony_ci with_x32 = true; 23862306a36Sopenharmony_ci } else if (ret == -ENOSYS) { 23962306a36Sopenharmony_ci info("x32 is not supported\n"); 24062306a36Sopenharmony_ci with_x32 = false; 24162306a36Sopenharmony_ci } else { 24262306a36Sopenharmony_ci fail("x32 getpid() returned %lld, but it should have returned either %lld or -ENOSYS\n", ret, (long long)mypid); 24362306a36Sopenharmony_ci with_x32 = false; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci sh->indent--; 24662306a36Sopenharmony_ci return with_x32; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic void test_syscalls_common(int msb) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci enum ptrace_pass pass = sh->ptrace_pass; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci run("Checking some common syscalls as 64 bit\n"); 25462306a36Sopenharmony_ci check_zero(msb, SYS_READ); 25562306a36Sopenharmony_ci check_zero(msb, SYS_WRITE); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci run("Checking some 64-bit only syscalls as 64 bit\n"); 25862306a36Sopenharmony_ci check_zero(msb, X64_READV); 25962306a36Sopenharmony_ci check_zero(msb, X64_WRITEV); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci run("Checking out of range system calls\n"); 26262306a36Sopenharmony_ci check_for(msb, -64, -2, -ENOSYS); 26362306a36Sopenharmony_ci if (pass >= PTP_FUZZRET) 26462306a36Sopenharmony_ci check_for(msb, -1, -1, MODIFIED_BY_PTRACE); 26562306a36Sopenharmony_ci else 26662306a36Sopenharmony_ci check_for(msb, -1, -1, -ENOSYS); 26762306a36Sopenharmony_ci check_for(msb, X32_BIT-64, X32_BIT-1, -ENOSYS); 26862306a36Sopenharmony_ci check_for(msb, -64-X32_BIT, -1-X32_BIT, -ENOSYS); 26962306a36Sopenharmony_ci check_for(msb, INT_MAX-64, INT_MAX-1, -ENOSYS); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic void test_syscalls_with_x32(int msb) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci /* 27562306a36Sopenharmony_ci * Syscalls 512-547 are "x32" syscalls. They are 27662306a36Sopenharmony_ci * intended to be called with the x32 (0x40000000) bit 27762306a36Sopenharmony_ci * set. Calling them without the x32 bit set is 27862306a36Sopenharmony_ci * nonsense and should not work. 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ci run("Checking x32 syscalls as 64 bit\n"); 28162306a36Sopenharmony_ci check_for(msb, 512, 547, -ENOSYS); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci run("Checking some common syscalls as x32\n"); 28462306a36Sopenharmony_ci check_zero(msb, SYS_READ | X32_BIT); 28562306a36Sopenharmony_ci check_zero(msb, SYS_WRITE | X32_BIT); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci run("Checking some x32 syscalls as x32\n"); 28862306a36Sopenharmony_ci check_zero(msb, X32_READV | X32_BIT); 28962306a36Sopenharmony_ci check_zero(msb, X32_WRITEV | X32_BIT); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci run("Checking some 64-bit syscalls as x32\n"); 29262306a36Sopenharmony_ci check_enosys(msb, X64_IOCTL | X32_BIT); 29362306a36Sopenharmony_ci check_enosys(msb, X64_READV | X32_BIT); 29462306a36Sopenharmony_ci check_enosys(msb, X64_WRITEV | X32_BIT); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic void test_syscalls_without_x32(int msb) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci run("Checking for absence of x32 system calls\n"); 30062306a36Sopenharmony_ci check_for(msb, 0 | X32_BIT, 999 | X32_BIT, -ENOSYS); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic void test_syscall_numbering(void) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci static const int msbs[] = { 30662306a36Sopenharmony_ci 0, 1, -1, X32_BIT-1, X32_BIT, X32_BIT-1, -X32_BIT, INT_MAX, 30762306a36Sopenharmony_ci INT_MIN, INT_MIN+1 30862306a36Sopenharmony_ci }; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci sh->indent++; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* 31362306a36Sopenharmony_ci * The MSB is supposed to be ignored, so we loop over a few 31462306a36Sopenharmony_ci * to test that out. 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_ci for (size_t i = 0; i < sizeof(msbs)/sizeof(msbs[0]); i++) { 31762306a36Sopenharmony_ci int msb = msbs[i]; 31862306a36Sopenharmony_ci run("Checking system calls with msb = %d (0x%x)\n", 31962306a36Sopenharmony_ci msb, msb); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci sh->indent++; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci test_syscalls_common(msb); 32462306a36Sopenharmony_ci if (with_x32) 32562306a36Sopenharmony_ci test_syscalls_with_x32(msb); 32662306a36Sopenharmony_ci else 32762306a36Sopenharmony_ci test_syscalls_without_x32(msb); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci sh->indent--; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci sh->indent--; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic void syscall_numbering_tracee(void) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci enum ptrace_pass pass; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (ptrace(PTRACE_TRACEME, 0, 0, 0)) { 34062306a36Sopenharmony_ci crit("Failed to request tracing\n"); 34162306a36Sopenharmony_ci return; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci raise(SIGSTOP); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci for (sh->ptrace_pass = pass = PTP_NOTHING; pass < PTP_DONE; 34662306a36Sopenharmony_ci sh->ptrace_pass = ++pass) { 34762306a36Sopenharmony_ci run("Running tests under ptrace: %s\n", ptrace_pass_name[pass]); 34862306a36Sopenharmony_ci test_syscall_numbering(); 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic void mess_with_syscall(pid_t testpid, enum ptrace_pass pass) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci struct user_regs_struct regs; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci sh->probing_syscall = false; /* Do this on entry only */ 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* For these, don't even getregs */ 35962306a36Sopenharmony_ci if (pass == PTP_NOTHING || pass == PTP_DONE) 36062306a36Sopenharmony_ci return; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci ptrace(PTRACE_GETREGS, testpid, NULL, ®s); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (regs.orig_rax != regs.rbx) { 36562306a36Sopenharmony_ci fail("orig_rax %#llx doesn't match syscall number %#llx\n", 36662306a36Sopenharmony_ci (unsigned long long)regs.orig_rax, 36762306a36Sopenharmony_ci (unsigned long long)regs.rbx); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci switch (pass) { 37162306a36Sopenharmony_ci case PTP_GETREGS: 37262306a36Sopenharmony_ci /* Just read, no writeback */ 37362306a36Sopenharmony_ci return; 37462306a36Sopenharmony_ci case PTP_WRITEBACK: 37562306a36Sopenharmony_ci /* Write back the same register state verbatim */ 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci case PTP_FUZZRET: 37862306a36Sopenharmony_ci regs.rax = MODIFIED_BY_PTRACE; 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci case PTP_FUZZHIGH: 38162306a36Sopenharmony_ci regs.rax = MODIFIED_BY_PTRACE; 38262306a36Sopenharmony_ci regs.orig_rax = regs.orig_rax | 0xffffffff00000000ULL; 38362306a36Sopenharmony_ci break; 38462306a36Sopenharmony_ci case PTP_INTNUM: 38562306a36Sopenharmony_ci regs.rax = MODIFIED_BY_PTRACE; 38662306a36Sopenharmony_ci regs.orig_rax = (int)regs.orig_rax; 38762306a36Sopenharmony_ci break; 38862306a36Sopenharmony_ci default: 38962306a36Sopenharmony_ci crit("invalid ptrace_pass\n"); 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci ptrace(PTRACE_SETREGS, testpid, NULL, ®s); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic void syscall_numbering_tracer(pid_t testpid) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci int wstatus; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci do { 40162306a36Sopenharmony_ci pid_t wpid = waitpid(testpid, &wstatus, 0); 40262306a36Sopenharmony_ci if (wpid < 0 && errno != EINTR) 40362306a36Sopenharmony_ci break; 40462306a36Sopenharmony_ci if (wpid != testpid) 40562306a36Sopenharmony_ci continue; 40662306a36Sopenharmony_ci if (!WIFSTOPPED(wstatus)) 40762306a36Sopenharmony_ci break; /* Thread exited? */ 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (sh->probing_syscall && WSTOPSIG(wstatus) == SIGTRAP) 41062306a36Sopenharmony_ci mess_with_syscall(testpid, sh->ptrace_pass); 41162306a36Sopenharmony_ci } while (sh->ptrace_pass != PTP_DONE && 41262306a36Sopenharmony_ci !ptrace(PTRACE_SYSCALL, testpid, NULL, NULL)); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci ptrace(PTRACE_DETACH, testpid, NULL, NULL); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* Wait for the child process to terminate */ 41762306a36Sopenharmony_ci while (waitpid(testpid, &wstatus, 0) != testpid || !WIFEXITED(wstatus)) 41862306a36Sopenharmony_ci /* wait some more */; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic void test_traced_syscall_numbering(void) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci pid_t testpid; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* Launch the test thread; this thread continues as the tracer thread */ 42662306a36Sopenharmony_ci testpid = fork(); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (testpid < 0) { 42962306a36Sopenharmony_ci crit("Unable to launch tracer process\n"); 43062306a36Sopenharmony_ci } else if (testpid == 0) { 43162306a36Sopenharmony_ci syscall_numbering_tracee(); 43262306a36Sopenharmony_ci _exit(0); 43362306a36Sopenharmony_ci } else { 43462306a36Sopenharmony_ci syscall_numbering_tracer(testpid); 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ciint main(void) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci unsigned int nerr; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* 44362306a36Sopenharmony_ci * It is quite likely to get a segfault on a failure, so make 44462306a36Sopenharmony_ci * sure the message gets out by setting stdout to nonbuffered. 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_ci setvbuf(stdout, NULL, _IONBF, 0); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* 44962306a36Sopenharmony_ci * Harmless file descriptor to work on... 45062306a36Sopenharmony_ci */ 45162306a36Sopenharmony_ci nullfd = open("/dev/null", O_RDWR); 45262306a36Sopenharmony_ci if (nullfd < 0) { 45362306a36Sopenharmony_ci crit("Unable to open /dev/null: %s\n", strerror(errno)); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* 45762306a36Sopenharmony_ci * Set up a block of shared memory... 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_ci sh = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ|PROT_WRITE, 46062306a36Sopenharmony_ci MAP_ANONYMOUS|MAP_SHARED, 0, 0); 46162306a36Sopenharmony_ci if (sh == MAP_FAILED) { 46262306a36Sopenharmony_ci crit("Unable to allocated shared memory block: %s\n", 46362306a36Sopenharmony_ci strerror(errno)); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci with_x32 = test_x32(); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci run("Running tests without ptrace...\n"); 46962306a36Sopenharmony_ci test_syscall_numbering(); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci test_traced_syscall_numbering(); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci nerr = sh->nerr; 47462306a36Sopenharmony_ci if (!nerr) { 47562306a36Sopenharmony_ci ok("All system calls succeeded or failed as expected\n"); 47662306a36Sopenharmony_ci return 0; 47762306a36Sopenharmony_ci } else { 47862306a36Sopenharmony_ci fail("A total of %u system call%s had incorrect behavior\n", 47962306a36Sopenharmony_ci nerr, nerr != 1 ? "s" : ""); 48062306a36Sopenharmony_ci return 1; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci} 483