12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a9c909ceSAndy Lutomirski /*
3a9c909ceSAndy Lutomirski  * syscall_nt.c - checks syscalls with NT set
4a9c909ceSAndy Lutomirski  * Copyright (c) 2014-2015 Andrew Lutomirski
5a9c909ceSAndy Lutomirski  *
6a9c909ceSAndy Lutomirski  * Some obscure user-space code requires the ability to make system calls
7a9c909ceSAndy Lutomirski  * with FLAGS.NT set.  Make sure it works.
8a9c909ceSAndy Lutomirski  */
9a9c909ceSAndy Lutomirski 
10a9c909ceSAndy Lutomirski #include <stdio.h>
11a9c909ceSAndy Lutomirski #include <unistd.h>
12a318beeaSAndy Lutomirski #include <string.h>
13a318beeaSAndy Lutomirski #include <signal.h>
14a318beeaSAndy Lutomirski #include <err.h>
15a9c909ceSAndy Lutomirski #include <sys/syscall.h>
16a9c909ceSAndy Lutomirski #include <asm/processor-flags.h>
17a9c909ceSAndy Lutomirski 
18a9c909ceSAndy Lutomirski #ifdef __x86_64__
19a9c909ceSAndy Lutomirski # define WIDTH "q"
20a9c909ceSAndy Lutomirski #else
21a9c909ceSAndy Lutomirski # define WIDTH "l"
22a9c909ceSAndy Lutomirski #endif
23a9c909ceSAndy Lutomirski 
24a318beeaSAndy Lutomirski static unsigned int nerrs;
25a318beeaSAndy Lutomirski 
26a9c909ceSAndy Lutomirski static unsigned long get_eflags(void)
27a9c909ceSAndy Lutomirski {
28a9c909ceSAndy Lutomirski 	unsigned long eflags;
29a9c909ceSAndy Lutomirski 	asm volatile ("pushf" WIDTH "\n\tpop" WIDTH " %0" : "=rm" (eflags));
30a9c909ceSAndy Lutomirski 	return eflags;
31a9c909ceSAndy Lutomirski }
32a9c909ceSAndy Lutomirski 
33a9c909ceSAndy Lutomirski static void set_eflags(unsigned long eflags)
34a9c909ceSAndy Lutomirski {
35a9c909ceSAndy Lutomirski 	asm volatile ("push" WIDTH " %0\n\tpopf" WIDTH
36a9c909ceSAndy Lutomirski 		      : : "rm" (eflags) : "flags");
37a9c909ceSAndy Lutomirski }
38a9c909ceSAndy Lutomirski 
39a318beeaSAndy Lutomirski static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
40a318beeaSAndy Lutomirski 		       int flags)
41a318beeaSAndy Lutomirski {
42a318beeaSAndy Lutomirski 	struct sigaction sa;
43a318beeaSAndy Lutomirski 	memset(&sa, 0, sizeof(sa));
44a318beeaSAndy Lutomirski 	sa.sa_sigaction = handler;
45a318beeaSAndy Lutomirski 	sa.sa_flags = SA_SIGINFO | flags;
46a318beeaSAndy Lutomirski 	sigemptyset(&sa.sa_mask);
47a318beeaSAndy Lutomirski 	if (sigaction(sig, &sa, 0))
48a318beeaSAndy Lutomirski 		err(1, "sigaction");
49a318beeaSAndy Lutomirski }
50a318beeaSAndy Lutomirski 
51a318beeaSAndy Lutomirski static void sigtrap(int sig, siginfo_t *si, void *ctx_void)
52a318beeaSAndy Lutomirski {
53a318beeaSAndy Lutomirski }
54a318beeaSAndy Lutomirski 
55a318beeaSAndy Lutomirski static void do_it(unsigned long extraflags)
56a318beeaSAndy Lutomirski {
57a318beeaSAndy Lutomirski 	unsigned long flags;
58a318beeaSAndy Lutomirski 
59a318beeaSAndy Lutomirski 	set_eflags(get_eflags() | extraflags);
60a318beeaSAndy Lutomirski 	syscall(SYS_getpid);
61a318beeaSAndy Lutomirski 	flags = get_eflags();
62a318beeaSAndy Lutomirski 	if ((flags & extraflags) == extraflags) {
63a318beeaSAndy Lutomirski 		printf("[OK]\tThe syscall worked and flags are still set\n");
64a318beeaSAndy Lutomirski 	} else {
65a318beeaSAndy Lutomirski 		printf("[FAIL]\tThe syscall worked but flags were cleared (flags = 0x%lx but expected 0x%lx set)\n",
66a318beeaSAndy Lutomirski 		       flags, extraflags);
67a318beeaSAndy Lutomirski 		nerrs++;
68a318beeaSAndy Lutomirski 	}
69a318beeaSAndy Lutomirski }
70a318beeaSAndy Lutomirski 
71a318beeaSAndy Lutomirski int main(void)
72a9c909ceSAndy Lutomirski {
73a9c909ceSAndy Lutomirski 	printf("[RUN]\tSet NT and issue a syscall\n");
74a318beeaSAndy Lutomirski 	do_it(X86_EFLAGS_NT);
75a318beeaSAndy Lutomirski 
76e4ef7de1SAndy Lutomirski 	printf("[RUN]\tSet AC and issue a syscall\n");
77e4ef7de1SAndy Lutomirski 	do_it(X86_EFLAGS_AC);
78e4ef7de1SAndy Lutomirski 
79e4ef7de1SAndy Lutomirski 	printf("[RUN]\tSet NT|AC and issue a syscall\n");
80e4ef7de1SAndy Lutomirski 	do_it(X86_EFLAGS_NT | X86_EFLAGS_AC);
81e4ef7de1SAndy Lutomirski 
82a318beeaSAndy Lutomirski 	/*
83a318beeaSAndy Lutomirski 	 * Now try it again with TF set -- TF forces returns via IRET in all
84a318beeaSAndy Lutomirski 	 * cases except non-ptregs-using 64-bit full fast path syscalls.
85a318beeaSAndy Lutomirski 	 */
86a318beeaSAndy Lutomirski 
87a318beeaSAndy Lutomirski 	sethandler(SIGTRAP, sigtrap, 0);
88a318beeaSAndy Lutomirski 
89e4ef7de1SAndy Lutomirski 	printf("[RUN]\tSet TF and issue a syscall\n");
90e4ef7de1SAndy Lutomirski 	do_it(X86_EFLAGS_TF);
91e4ef7de1SAndy Lutomirski 
92a318beeaSAndy Lutomirski 	printf("[RUN]\tSet NT|TF and issue a syscall\n");
93a318beeaSAndy Lutomirski 	do_it(X86_EFLAGS_NT | X86_EFLAGS_TF);
94a318beeaSAndy Lutomirski 
95e4ef7de1SAndy Lutomirski 	printf("[RUN]\tSet AC|TF and issue a syscall\n");
96e4ef7de1SAndy Lutomirski 	do_it(X86_EFLAGS_AC | X86_EFLAGS_TF);
97e4ef7de1SAndy Lutomirski 
98e4ef7de1SAndy Lutomirski 	printf("[RUN]\tSet NT|AC|TF and issue a syscall\n");
99e4ef7de1SAndy Lutomirski 	do_it(X86_EFLAGS_NT | X86_EFLAGS_AC | X86_EFLAGS_TF);
100e4ef7de1SAndy Lutomirski 
101a318beeaSAndy Lutomirski 	return nerrs == 0 ? 0 : 1;
102a9c909ceSAndy Lutomirski }
103