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 static short watchpoint;
26 static pid_t child_pid;
27
child_main(void)28 static int child_main(void)
29 {
30 SAFE_PTRACE(PTRACE_TRACEME, 0, NULL, NULL);
31 raise(SIGSTOP);
32 /* wait for SIGCONT from parent */
33
34 asm volatile(
35 "mov %%ss, %0\n"
36 "mov %0, %%ss\n"
37 "int $3\n"
38 : "+m" (watchpoint)
39 );
40
41 return 0;
42 }
43
run(void)44 static void run(void)
45 {
46 int status;
47
48 #if defined(__i386__) || defined(__x86_64__)
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 #endif
64
65 while (1) {
66 if (SAFE_WAITPID(child_pid, &status, 0) != child_pid)
67 tst_brk(TBROK, "Received event from unexpected PID");
68
69 if (WIFEXITED(status)) {
70 child_pid = 0;
71 break;
72 }
73
74 if (WIFSTOPPED(status)) {
75 SAFE_PTRACE(PTRACE_CONT, child_pid, NULL, NULL);
76 continue;
77 }
78
79 tst_brk(TBROK, "Unexpected event from child");
80 }
81
82 tst_res(TPASS, "We're still here. Nothing bad happened, probably.");
83 }
84
cleanup(void)85 static void cleanup(void)
86 {
87 /* Main process terminated by tst_brk() with child still paused */
88 if (child_pid)
89 SAFE_KILL(child_pid, SIGKILL);
90 }
91
92 static struct tst_test test = {
93 .test_all = run,
94 .cleanup = cleanup,
95 .forks_child = 1,
96 .supported_archs = (const char *const []) {
97 "x86",
98 "x86_64",
99 NULL
100 },
101 .tags = (const struct tst_tag[]) {
102 {"linux-git", "d8ba61ba58c8"},
103 {"CVE", "2018-8897"},
104 {}
105 }
106 };
107