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