Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
19static unsigned int nerrs;
20
21static void sigtrap(int sig, siginfo_t *si, void *ctx_void)
22{
23}
24
25static 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
42int 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}