• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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