1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2018 SUSE LLC <nstange@suse.de>
4 * Copyright (C) 2020 SUSE LLC <mdoucha@suse.cz>
5 *
6 * CVE-2018-8897
7 *
8 * Test that the MOV SS instruction touching a ptrace watchpoint followed by
9 * INT3 breakpoint is handled correctly by the kernel. Kernel crash fixed in:
10 *
11 * commit d8ba61ba58c88d5207c1ba2f7d9a2280e7d03be9
12 * Author: Andy Lutomirski <luto@kernel.org>
13 * Date: Thu Jul 23 15:37:48 2015 -0700
14 *
15 * x86/entry/64: Don't use IST entry for #BP stack
16 */
17
18 #include <stdlib.h>
19 #include <stddef.h>
20 #include <sys/ptrace.h>
21 #include <sys/user.h>
22 #include <signal.h>
23 #include "tst_test.h"
24
25 #if defined(__i386__) || defined(__x86_64__)
26 static short watchpoint;
27 static pid_t child_pid;
28
child_main(void)29 static int child_main(void)
30 {
31 SAFE_PTRACE(PTRACE_TRACEME, 0, NULL, NULL);
32 raise(SIGSTOP);
33 /* wait for SIGCONT from parent */
34
35 asm volatile(
36 "mov %%ss, %0\n"
37 "mov %0, %%ss\n"
38 "int $3\n"
39 : "+m" (watchpoint)
40 );
41
42 return 0;
43 }
44
run(void)45 static void run(void)
46 {
47 int status;
48
49 child_pid = SAFE_FORK();
50
51 if (!child_pid) {
52 exit(child_main());
53 }
54
55 if (SAFE_WAITPID(child_pid, &status, 0) != child_pid)
56 tst_brk(TBROK, "Received event from unexpected PID");
57
58 SAFE_PTRACE(PTRACE_POKEUSER, child_pid,
59 (void *)offsetof(struct user, u_debugreg[0]), &watchpoint);
60 SAFE_PTRACE(PTRACE_POKEUSER, child_pid,
61 (void *)offsetof(struct user, u_debugreg[7]), (void *)0x30001);
62 SAFE_PTRACE(PTRACE_CONT, child_pid, NULL, NULL);
63
64 while (1) {
65 if (SAFE_WAITPID(child_pid, &status, 0) != child_pid)
66 tst_brk(TBROK, "Received event from unexpected PID");
67
68 if (WIFEXITED(status)) {
69 child_pid = 0;
70 break;
71 }
72
73 if (WIFSTOPPED(status)) {
74 SAFE_PTRACE(PTRACE_CONT, child_pid, NULL, NULL);
75 continue;
76 }
77
78 tst_brk(TBROK, "Unexpected event from child");
79 }
80
81 tst_res(TPASS, "We're still here. Nothing bad happened, probably.");
82 }
83
cleanup(void)84 static void cleanup(void)
85 {
86 /* Main process terminated by tst_brk() with child still paused */
87 if (child_pid)
88 SAFE_KILL(child_pid, SIGKILL);
89 }
90
91 static struct tst_test test = {
92 .test_all = run,
93 .cleanup = cleanup,
94 .forks_child = 1,
95 .tags = (const struct tst_tag[]) {
96 {"linux-git", "d8ba61ba58c8"},
97 {"CVE", "2018-8897"},
98 {}
99 }
100 };
101 #else
102 TST_TEST_TCONF("This test is only supported on x86 systems");
103 #endif
104