1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2018 Michael Moese <mmoese@suse.com>
4 */
5 /*
6 * Test for CVE-2017-17052, original reproducer taken from kernel commit:
7 * 2b7e8665b4ff51c034c55df3cff76518d1a9ee3a
8 *
9 * CAUTION!!
10 * This test will crash unpatched kernels!
11 * Use at your own risk!
12 *
13 */
14
15 #include <unistd.h>
16 #include <pthread.h>
17 #include <sys/wait.h>
18 #include <sys/syscall.h>
19 #include <sys/types.h>
20 #include <stdlib.h>
21
22 #include "tst_test.h"
23 #include "tst_safe_pthread.h"
24 #include "lapi/syscalls.h"
25
26 #define RUNS 4
27 #define EXEC_USEC 400000
28
29 static int *do_exit;
30
setup(void)31 static void setup(void)
32 {
33 do_exit = SAFE_MMAP(NULL, sizeof(*do_exit), PROT_READ|PROT_WRITE,
34 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
35
36 *do_exit = 0;
37 }
38
cleanup(void)39 static void cleanup(void)
40 {
41 SAFE_MUNMAP(do_exit, sizeof(*do_exit));
42 }
43
mmap_thread(void * arg)44 static void *mmap_thread(void *arg)
45 {
46 for (;;) {
47 SAFE_MMAP(NULL, 0x1000000, PROT_READ,
48 MAP_POPULATE|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
49 }
50
51 return arg;
52 }
53
fork_thread(void * arg)54 static void *fork_thread(void *arg)
55 {
56 usleep(rand() % 10000);
57 SAFE_FORK();
58
59 return arg;
60 }
61
do_test_fork(void)62 static void do_test_fork(void)
63 {
64 int status;
65
66 SAFE_FORK();
67 SAFE_FORK();
68 SAFE_FORK();
69
70 for(;;) {
71 if (SAFE_FORK() == 0) {
72 pthread_t t;
73
74 SAFE_PTHREAD_CREATE(&t, NULL, mmap_thread, NULL);
75 SAFE_PTHREAD_CREATE(&t, NULL, fork_thread, NULL);
76 usleep(rand() % 10000);
77 syscall(__NR_exit_group, 0);
78 }
79 SAFE_WAIT(&status);
80 if (*do_exit)
81 exit(0);
82 }
83 }
84
run(void)85 static void run(void)
86 {
87 pid_t pid;
88 int status;
89 volatile int run = 0;
90
91 while (run < RUNS) {
92 *do_exit = 0;
93 pid = SAFE_FORK();
94
95 if (pid == 0) {
96 do_test_fork();
97 } else {
98 usleep(EXEC_USEC);
99 *do_exit = 1;
100 }
101
102 SAFE_WAIT(&status);
103 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
104 tst_res(TINFO, "run %d passed", run);
105 } else {
106 tst_res(TFAIL, "child %s", tst_strstatus(status));
107 }
108
109 run++;
110 }
111
112 if (run == RUNS)
113 tst_res(TPASS, "kernel survived %d runs", run);
114 else
115 tst_res(TFAIL, "something strange happened");
116 }
117
118 static struct tst_test test = {
119 .forks_child = 1,
120 .cleanup = cleanup,
121 .setup = setup,
122 .test_all = run,
123 .tags = (const struct tst_tag[]) {
124 {"linux-git", "2b7e8665b4ff"},
125 {"CVE", "2017-17052"},
126 {}
127 }
128 };
129