1 /*
2 * Copyright (c) 2018 Michael Moese <mmoese@suse.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /*
18 * Test for CVE-2017-17052, original reproducer taken from kernel commit:
19 * 2b7e8665b4ff51c034c55df3cff76518d1a9ee3a
20 *
21 * CAUTION!!
22 * This test will crash unpatched kernels!
23 * Use at your own risk!
24 *
25 */
26
27 #include <unistd.h>
28 #include <pthread.h>
29 #include <sys/wait.h>
30 #include <sys/syscall.h>
31 #include <sys/types.h>
32 #include <stdlib.h>
33
34 #include "tst_test.h"
35 #include "tst_safe_pthread.h"
36 #include "lapi/syscalls.h"
37
38 #define RUNS 4
39 #define EXEC_USEC 400000
40
41 static int *do_exit;
42
setup(void)43 static void setup(void)
44 {
45 do_exit = SAFE_MMAP(NULL, sizeof(*do_exit), PROT_READ|PROT_WRITE,
46 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
47
48 *do_exit = 0;
49 }
50
cleanup(void)51 static void cleanup(void)
52 {
53 SAFE_MUNMAP(do_exit, sizeof(*do_exit));
54 }
55
mmap_thread(void * arg)56 static void *mmap_thread(void *arg)
57 {
58 for (;;) {
59 SAFE_MMAP(NULL, 0x1000000, PROT_READ,
60 MAP_POPULATE|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
61 if (*do_exit)
62 exit(0);
63 }
64
65 return arg;
66 }
67
fork_thread(void * arg)68 static void *fork_thread(void *arg)
69 {
70 if (*do_exit)
71 exit(0);
72
73 usleep(rand() % 10000);
74 SAFE_FORK();
75
76 return arg;
77 }
78
do_test_fork(void)79 static void do_test_fork(void)
80 {
81 int status;
82
83 SAFE_FORK();
84 SAFE_FORK();
85 SAFE_FORK();
86
87 for(;;) {
88 if (SAFE_FORK() == 0) {
89 pthread_t t;
90
91 SAFE_PTHREAD_CREATE(&t, NULL, mmap_thread, NULL);
92 SAFE_PTHREAD_CREATE(&t, NULL, fork_thread, NULL);
93 usleep(rand() % 10000);
94 syscall(__NR_exit_group, 0);
95 }
96 SAFE_WAIT(&status);
97 if (*do_exit)
98 exit(0);
99 }
100 }
101
run(void)102 static void run(void)
103 {
104 pid_t pid;
105 volatile int run = 0;
106
107 while (run < RUNS) {
108 pid = SAFE_FORK();
109
110 if (pid == 0) {
111 do_test_fork();
112 } else {
113 usleep(EXEC_USEC);
114 *do_exit = 1;
115 }
116 tst_res(TINFO, "run %d passed", run);
117 run++;
118 }
119
120 if (run == RUNS)
121 tst_res(TPASS, "kernel survived %d runs", run);
122 else
123 tst_res(TBROK, "something strange happened");
124 }
125
126 static struct tst_test test = {
127 .forks_child = 1,
128 .cleanup = cleanup,
129 .setup = setup,
130 .test_all = run,
131 };
132