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 
17cced0b24SAndy Lutomirski #include "helpers.h"
18a9c909ceSAndy Lutomirski 
19a318beeaSAndy Lutomirski static unsigned int nerrs;
20a318beeaSAndy Lutomirski 
sethandler(int sig,void (* handler)(int,siginfo_t *,void *),int flags)21a318beeaSAndy Lutomirski static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
22a318beeaSAndy Lutomirski 		       int flags)
23a318beeaSAndy Lutomirski {
24a318beeaSAndy Lutomirski 	struct sigaction sa;
25a318beeaSAndy Lutomirski 	memset(&sa, 0, sizeof(sa));
26a318beeaSAndy Lutomirski 	sa.sa_sigaction = handler;
27a318beeaSAndy Lutomirski 	sa.sa_flags = SA_SIGINFO | flags;
28a318beeaSAndy Lutomirski 	sigemptyset(&sa.sa_mask);
29a318beeaSAndy Lutomirski 	if (sigaction(sig, &sa, 0))
30a318beeaSAndy Lutomirski 		err(1, "sigaction");
31a318beeaSAndy Lutomirski }
32a318beeaSAndy Lutomirski 
sigtrap(int sig,siginfo_t * si,void * ctx_void)33a318beeaSAndy Lutomirski static void sigtrap(int sig, siginfo_t *si, void *ctx_void)
34a318beeaSAndy Lutomirski {
35a318beeaSAndy Lutomirski }
36a318beeaSAndy Lutomirski 
do_it(unsigned long extraflags)37a318beeaSAndy Lutomirski static void do_it(unsigned long extraflags)
38a318beeaSAndy Lutomirski {
39a318beeaSAndy Lutomirski 	unsigned long flags;
40a318beeaSAndy Lutomirski 
41a318beeaSAndy Lutomirski 	set_eflags(get_eflags() | extraflags);
42a318beeaSAndy Lutomirski 	syscall(SYS_getpid);
43a318beeaSAndy Lutomirski 	flags = get_eflags();
44a61fa279SAndy Lutomirski 	set_eflags(X86_EFLAGS_IF | X86_EFLAGS_FIXED);
45a318beeaSAndy Lutomirski 	if ((flags & extraflags) == extraflags) {
46a318beeaSAndy Lutomirski 		printf("[OK]\tThe syscall worked and flags are still set\n");
47a318beeaSAndy Lutomirski 	} else {
48a318beeaSAndy Lutomirski 		printf("[FAIL]\tThe syscall worked but flags were cleared (flags = 0x%lx but expected 0x%lx set)\n",
49a318beeaSAndy Lutomirski 		       flags, extraflags);
50a318beeaSAndy Lutomirski 		nerrs++;
51a318beeaSAndy Lutomirski 	}
52a318beeaSAndy Lutomirski }
53a318beeaSAndy Lutomirski 
main(void)54a318beeaSAndy Lutomirski int main(void)
55a9c909ceSAndy Lutomirski {
56a9c909ceSAndy Lutomirski 	printf("[RUN]\tSet NT and issue a syscall\n");
57a318beeaSAndy Lutomirski 	do_it(X86_EFLAGS_NT);
58a318beeaSAndy Lutomirski 
59e4ef7de1SAndy Lutomirski 	printf("[RUN]\tSet AC and issue a syscall\n");
60e4ef7de1SAndy Lutomirski 	do_it(X86_EFLAGS_AC);
61e4ef7de1SAndy Lutomirski 
62e4ef7de1SAndy Lutomirski 	printf("[RUN]\tSet NT|AC and issue a syscall\n");
63e4ef7de1SAndy Lutomirski 	do_it(X86_EFLAGS_NT | X86_EFLAGS_AC);
64e4ef7de1SAndy Lutomirski 
65a318beeaSAndy Lutomirski 	/*
66a318beeaSAndy Lutomirski 	 * Now try it again with TF set -- TF forces returns via IRET in all
67a318beeaSAndy Lutomirski 	 * cases except non-ptregs-using 64-bit full fast path syscalls.
68a318beeaSAndy Lutomirski 	 */
69a318beeaSAndy Lutomirski 
70a318beeaSAndy Lutomirski 	sethandler(SIGTRAP, sigtrap, 0);
71a318beeaSAndy Lutomirski 
72e4ef7de1SAndy Lutomirski 	printf("[RUN]\tSet TF and issue a syscall\n");
73e4ef7de1SAndy Lutomirski 	do_it(X86_EFLAGS_TF);
74e4ef7de1SAndy Lutomirski 
75a318beeaSAndy Lutomirski 	printf("[RUN]\tSet NT|TF and issue a syscall\n");
76a318beeaSAndy Lutomirski 	do_it(X86_EFLAGS_NT | X86_EFLAGS_TF);
77a318beeaSAndy Lutomirski 
78e4ef7de1SAndy Lutomirski 	printf("[RUN]\tSet AC|TF and issue a syscall\n");
79e4ef7de1SAndy Lutomirski 	do_it(X86_EFLAGS_AC | X86_EFLAGS_TF);
80e4ef7de1SAndy Lutomirski 
81e4ef7de1SAndy Lutomirski 	printf("[RUN]\tSet NT|AC|TF and issue a syscall\n");
82e4ef7de1SAndy Lutomirski 	do_it(X86_EFLAGS_NT | X86_EFLAGS_AC | X86_EFLAGS_TF);
83e4ef7de1SAndy Lutomirski 
843c73b81aSAndy Lutomirski 	/*
853c73b81aSAndy Lutomirski 	 * Now try DF.  This is evil and it's plausible that we will crash
863c73b81aSAndy Lutomirski 	 * glibc, but glibc would have to do something rather surprising
873c73b81aSAndy Lutomirski 	 * for this to happen.
883c73b81aSAndy Lutomirski 	 */
893c73b81aSAndy Lutomirski 	printf("[RUN]\tSet DF and issue a syscall\n");
903c73b81aSAndy Lutomirski 	do_it(X86_EFLAGS_DF);
913c73b81aSAndy Lutomirski 
923c73b81aSAndy Lutomirski 	printf("[RUN]\tSet TF|DF and issue a syscall\n");
933c73b81aSAndy Lutomirski 	do_it(X86_EFLAGS_TF | X86_EFLAGS_DF);
943c73b81aSAndy Lutomirski 
95a318beeaSAndy Lutomirski 	return nerrs == 0 ? 0 : 1;
96a9c909ceSAndy Lutomirski }
97