• 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  * Based on the reproducer from Eric Biggers.
5  */
6 
7 /*\
8  * [Description]
9  *
10  * Test for CVE-2017-17052, which was fixed in kernel v4.13:
11  * 2b7e8665b4ff ("fork: fix incorrect fput of ->exe_file causing use-after-free").
12  *
13  * Based on the reproducer taken from fixing kernel commit.
14  *
15  * CAUTION! If your system is vulnerable to this CVE, the crashes kernel.
16  */
17 
18 #include <unistd.h>
19 #include <pthread.h>
20 #include <sys/wait.h>
21 #include <sys/syscall.h>
22 #include <sys/types.h>
23 #include <stdlib.h>
24 
25 #include "tst_test.h"
26 #include "tst_safe_pthread.h"
27 #include "lapi/syscalls.h"
28 
29 #define RUNS	   4
30 #define EXEC_USEC  400000
31 
32 static int *do_exit;
33 
setup(void)34 static void setup(void)
35 {
36 	do_exit = SAFE_MMAP(NULL, sizeof(*do_exit), PROT_READ|PROT_WRITE,
37 		            MAP_SHARED | MAP_ANONYMOUS, -1, 0);
38 
39 	*do_exit = 0;
40 }
41 
cleanup(void)42 static void cleanup(void)
43 {
44 	SAFE_MUNMAP(do_exit, sizeof(*do_exit));
45 }
46 
mmap_thread(void * arg)47 static void *mmap_thread(void *arg)
48 {
49 	for (;;) {
50 		SAFE_MMAP(NULL, 0x1000000, PROT_READ,
51 				MAP_POPULATE|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
52 	}
53 
54 	return arg;
55 }
56 
fork_thread(void * arg)57 static void *fork_thread(void *arg)
58 {
59 	usleep(rand() % 10000);
60 	SAFE_FORK();
61 
62 	return arg;
63 }
64 
do_test_fork(void)65 static void do_test_fork(void)
66 {
67 	int status;
68 
69 	SAFE_FORK();
70 	SAFE_FORK();
71 	SAFE_FORK();
72 
73 	for(;;) {
74 		if (SAFE_FORK() == 0) {
75 			pthread_t t;
76 
77 			SAFE_PTHREAD_CREATE(&t, NULL, mmap_thread, NULL);
78 			SAFE_PTHREAD_CREATE(&t, NULL, fork_thread, NULL);
79 			usleep(rand() % 10000);
80 			syscall(__NR_exit_group, 0);
81 		}
82 		SAFE_WAIT(&status);
83 		if (*do_exit)
84 			exit(0);
85 	}
86 }
87 
run(void)88 static void run(void)
89 {
90 	pid_t pid;
91 	int status;
92 	volatile int run = 0;
93 
94 	while (run < RUNS) {
95 		*do_exit = 0;
96 		pid = SAFE_FORK();
97 
98 		if (pid == 0) {
99 			do_test_fork();
100 		} else {
101 			usleep(EXEC_USEC);
102 			*do_exit = 1;
103 		}
104 
105 		SAFE_WAIT(&status);
106 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
107 			tst_res(TINFO, "run %d passed", run);
108 		} else {
109 			tst_res(TFAIL, "child %s", tst_strstatus(status));
110 		}
111 
112 		run++;
113 	}
114 
115 	if (run == RUNS)
116 		tst_res(TPASS, "kernel survived %d runs", run);
117 	else
118 		tst_res(TFAIL, "something strange happened");
119 }
120 
121 static struct tst_test test = {
122 	.forks_child = 1,
123 	.cleanup = cleanup,
124 	.setup = setup,
125 	.test_all = run,
126 	.tags = (const struct tst_tag[]) {
127 		{"linux-git", "2b7e8665b4ff"},
128 		{"CVE", "2017-17052"},
129 		{}
130 	}
131 };
132