xref: /openbsd-src/regress/sys/kern/pipe/test-close.c (revision f82cc8201f7fe4f6ceac1fe6b87106df163afa0a)
1 /*	$OpenBSD: test-close.c,v 1.1 2020/06/29 18:25:37 anton Exp $	*/
2 
3 /*
4  * Copyright (c) 2019 Anton Lindqvist <anton@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <err.h>
20 #include <pthread.h>
21 #include <signal.h>
22 #include <unistd.h>
23 
24 #include "pipe.h"
25 
26 struct context {
27 	volatile sig_atomic_t *c_alive;
28 	int c_fd;
29 };
30 
31 static void *close_thread(void *);
32 static void sighandler(int);
33 
34 static volatile sig_atomic_t alive = 1;
35 
36 /*
37  * Regression during close(2) causing a use-after-free.
38  * The main thread repeatedly creates a new pipe which two other threads tries
39  * to close. By default, 100 iterations is performed.
40  */
41 int
test_close_race(void)42 test_close_race(void)
43 {
44 	pthread_t th1, th2;
45 	struct context ctx1, ctx2;
46 	int nrounds = 100;
47 	int pip[2];
48 	int error;
49 
50 	if (signal(SIGINT, sighandler) == SIG_ERR)
51 		err(1, "signal");
52 
53 	ctx1.c_alive = &alive;
54 	ctx1.c_fd = 3;
55 	error = pthread_create(&th1, NULL, close_thread, &ctx1);
56 	if (error)
57 		errc(1, error, "pthread_create");
58 	ctx2.c_alive = &alive;
59 	ctx2.c_fd = 4;
60 	error = pthread_create(&th2, NULL, close_thread, &ctx2);
61 	if (error)
62 		errc(1, error, "pthread_create");
63 
64 	while (alive) {
65 		if (!infinity && nrounds-- == 0)
66 			alive = 0;
67 
68 		if (pipe(pip) == -1)
69 			err(1, "pipe");
70 		if (pip[0] != 3)
71 			close(pip[0]);
72 		if (pip[1] != 4)
73 			close(pip[1]);
74 	}
75 
76 	error = pthread_join(th1, NULL);
77 	if (error)
78 		errc(1, error, "pthread_join");
79 	error = pthread_join(th2, NULL);
80 	if (error)
81 		errc(1, error, "pthread_join");
82 
83 	return 0;
84 }
85 
86 static void *
close_thread(void * arg)87 close_thread(void *arg)
88 {
89 	const struct context *ctx = arg;
90 
91 	while (*ctx->c_alive)
92 		close(ctx->c_fd);
93 
94 	return NULL;
95 }
96 
97 static void
sighandler(int signo)98 sighandler(int signo)
99 {
100 
101 	alive = 0;
102 }
103