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