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