162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * syscall_nt.c - checks syscalls with NT set 462306a36Sopenharmony_ci * Copyright (c) 2014-2015 Andrew Lutomirski 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Some obscure user-space code requires the ability to make system calls 762306a36Sopenharmony_ci * with FLAGS.NT set. Make sure it works. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <stdio.h> 1162306a36Sopenharmony_ci#include <unistd.h> 1262306a36Sopenharmony_ci#include <string.h> 1362306a36Sopenharmony_ci#include <signal.h> 1462306a36Sopenharmony_ci#include <err.h> 1562306a36Sopenharmony_ci#include <sys/syscall.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "helpers.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic unsigned int nerrs; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), 2262306a36Sopenharmony_ci int flags) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct sigaction sa; 2562306a36Sopenharmony_ci memset(&sa, 0, sizeof(sa)); 2662306a36Sopenharmony_ci sa.sa_sigaction = handler; 2762306a36Sopenharmony_ci sa.sa_flags = SA_SIGINFO | flags; 2862306a36Sopenharmony_ci sigemptyset(&sa.sa_mask); 2962306a36Sopenharmony_ci if (sigaction(sig, &sa, 0)) 3062306a36Sopenharmony_ci err(1, "sigaction"); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic void sigtrap(int sig, siginfo_t *si, void *ctx_void) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic void do_it(unsigned long extraflags) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci unsigned long flags; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci set_eflags(get_eflags() | extraflags); 4262306a36Sopenharmony_ci syscall(SYS_getpid); 4362306a36Sopenharmony_ci flags = get_eflags(); 4462306a36Sopenharmony_ci set_eflags(X86_EFLAGS_IF | X86_EFLAGS_FIXED); 4562306a36Sopenharmony_ci if ((flags & extraflags) == extraflags) { 4662306a36Sopenharmony_ci printf("[OK]\tThe syscall worked and flags are still set\n"); 4762306a36Sopenharmony_ci } else { 4862306a36Sopenharmony_ci printf("[FAIL]\tThe syscall worked but flags were cleared (flags = 0x%lx but expected 0x%lx set)\n", 4962306a36Sopenharmony_ci flags, extraflags); 5062306a36Sopenharmony_ci nerrs++; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciint main(void) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci printf("[RUN]\tSet NT and issue a syscall\n"); 5762306a36Sopenharmony_ci do_it(X86_EFLAGS_NT); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci printf("[RUN]\tSet AC and issue a syscall\n"); 6062306a36Sopenharmony_ci do_it(X86_EFLAGS_AC); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci printf("[RUN]\tSet NT|AC and issue a syscall\n"); 6362306a36Sopenharmony_ci do_it(X86_EFLAGS_NT | X86_EFLAGS_AC); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* 6662306a36Sopenharmony_ci * Now try it again with TF set -- TF forces returns via IRET in all 6762306a36Sopenharmony_ci * cases except non-ptregs-using 64-bit full fast path syscalls. 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci sethandler(SIGTRAP, sigtrap, 0); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci printf("[RUN]\tSet TF and issue a syscall\n"); 7362306a36Sopenharmony_ci do_it(X86_EFLAGS_TF); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci printf("[RUN]\tSet NT|TF and issue a syscall\n"); 7662306a36Sopenharmony_ci do_it(X86_EFLAGS_NT | X86_EFLAGS_TF); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci printf("[RUN]\tSet AC|TF and issue a syscall\n"); 7962306a36Sopenharmony_ci do_it(X86_EFLAGS_AC | X86_EFLAGS_TF); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci printf("[RUN]\tSet NT|AC|TF and issue a syscall\n"); 8262306a36Sopenharmony_ci do_it(X86_EFLAGS_NT | X86_EFLAGS_AC | X86_EFLAGS_TF); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* 8562306a36Sopenharmony_ci * Now try DF. This is evil and it's plausible that we will crash 8662306a36Sopenharmony_ci * glibc, but glibc would have to do something rather surprising 8762306a36Sopenharmony_ci * for this to happen. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci printf("[RUN]\tSet DF and issue a syscall\n"); 9062306a36Sopenharmony_ci do_it(X86_EFLAGS_DF); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci printf("[RUN]\tSet TF|DF and issue a syscall\n"); 9362306a36Sopenharmony_ci do_it(X86_EFLAGS_TF | X86_EFLAGS_DF); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return nerrs == 0 ? 0 : 1; 9662306a36Sopenharmony_ci} 97