1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * syscall_nt.c - checks syscalls with NT set
4  * Copyright (c) 2014-2015 Andrew Lutomirski
5  *
6  * Some obscure user-space code requires the ability to make system calls
7  * with FLAGS.NT set.  Make sure it works.
8  */
9 
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <signal.h>
14 #include <err.h>
15 #include <sys/syscall.h>
16 
17 #include "helpers.h"
18 
19 static unsigned int nerrs;
20 
sigtrap(int sig,siginfo_t * si,void * ctx_void)21 static void sigtrap(int sig, siginfo_t *si, void *ctx_void)
22 {
23 }
24 
do_it(unsigned long extraflags)25 static void do_it(unsigned long extraflags)
26 {
27 	unsigned long flags;
28 
29 	set_eflags(get_eflags() | extraflags);
30 	syscall(SYS_getpid);
31 	flags = get_eflags();
32 	set_eflags(X86_EFLAGS_IF | X86_EFLAGS_FIXED);
33 	if ((flags & extraflags) == extraflags) {
34 		printf("[OK]\tThe syscall worked and flags are still set\n");
35 	} else {
36 		printf("[FAIL]\tThe syscall worked but flags were cleared (flags = 0x%lx but expected 0x%lx set)\n",
37 		       flags, extraflags);
38 		nerrs++;
39 	}
40 }
41 
main(void)42 int main(void)
43 {
44 	printf("[RUN]\tSet NT and issue a syscall\n");
45 	do_it(X86_EFLAGS_NT);
46 
47 	printf("[RUN]\tSet AC and issue a syscall\n");
48 	do_it(X86_EFLAGS_AC);
49 
50 	printf("[RUN]\tSet NT|AC and issue a syscall\n");
51 	do_it(X86_EFLAGS_NT | X86_EFLAGS_AC);
52 
53 	/*
54 	 * Now try it again with TF set -- TF forces returns via IRET in all
55 	 * cases except non-ptregs-using 64-bit full fast path syscalls.
56 	 */
57 
58 	sethandler(SIGTRAP, sigtrap, 0);
59 
60 	printf("[RUN]\tSet TF and issue a syscall\n");
61 	do_it(X86_EFLAGS_TF);
62 
63 	printf("[RUN]\tSet NT|TF and issue a syscall\n");
64 	do_it(X86_EFLAGS_NT | X86_EFLAGS_TF);
65 
66 	printf("[RUN]\tSet AC|TF and issue a syscall\n");
67 	do_it(X86_EFLAGS_AC | X86_EFLAGS_TF);
68 
69 	printf("[RUN]\tSet NT|AC|TF and issue a syscall\n");
70 	do_it(X86_EFLAGS_NT | X86_EFLAGS_AC | X86_EFLAGS_TF);
71 
72 	/*
73 	 * Now try DF.  This is evil and it's plausible that we will crash
74 	 * glibc, but glibc would have to do something rather surprising
75 	 * for this to happen.
76 	 */
77 	printf("[RUN]\tSet DF and issue a syscall\n");
78 	do_it(X86_EFLAGS_DF);
79 
80 	printf("[RUN]\tSet TF|DF and issue a syscall\n");
81 	do_it(X86_EFLAGS_TF | X86_EFLAGS_DF);
82 
83 	return nerrs == 0 ? 0 : 1;
84 }
85