1 /*-
2 * Copyright (c) 2006 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 /*
28 * Attempts to exercise UNIX domain socket races relating to the non-atomic
29 * connect-and-send properties of sendto(). As the result of such a race is
30 * a kernel panic, this test simply completes or doesn't.
31 *
32 * XXX: Despite implementing support for sendto() on stream sockets with
33 * implied connect, the appropriate flag isn't set in the FreeBSD kernel so
34 * it does not work. For now, don't call the stream test.
35 */
36
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/un.h>
40
41 #include <err.h>
42 #include <signal.h>
43 #include <string.h>
44 #include <unistd.h>
45
46 #define ITERATIONS 1000000
47
48 static char socket_path[] = "tmp.XXXXXX";
49
50 static void
stream_server(int listenfd)51 stream_server(int listenfd)
52 {
53 int acceptfd;
54
55 while (1) {
56 acceptfd = accept(listenfd, NULL, NULL);
57 if (acceptfd < 0) {
58 warn("stream_server: accept");
59 continue;
60 }
61 sleep(1);
62 close(acceptfd);
63 }
64 }
65
66 static void
stream_client(void)67 stream_client(void)
68 {
69 struct sockaddr_un sun;
70 ssize_t len;
71 char c = 0;
72 int fd, i;
73
74 bzero(&sun, sizeof(sun));
75 sun.sun_len = sizeof(sun);
76 sun.sun_family = AF_UNIX;
77 strcpy(sun.sun_path, socket_path);
78 for (i = 0; i < ITERATIONS; i++) {
79 fd = socket(PF_UNIX, SOCK_STREAM, 0);
80 if (fd < 0) {
81 warn("stream_client: socket");
82 return;
83 }
84 len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun,
85 sizeof(sun));
86 if (len < 0)
87 warn("stream_client: sendto");
88 close(fd);
89 }
90 }
91
92 static void
stream_test(void)93 stream_test(void)
94 {
95 struct sockaddr_un sun;
96 pid_t childpid;
97 int listenfd;
98
99 listenfd = socket(PF_UNIX, SOCK_STREAM, 0);
100 if (listenfd < 0)
101 err(-1, "stream_test: socket");
102
103 bzero(&sun, sizeof(sun));
104 sun.sun_len = sizeof(sun);
105 sun.sun_family = AF_UNIX;
106 strcpy(sun.sun_path, socket_path);
107
108 if (bind(listenfd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
109 err(-1, "stream_test: bind");
110
111 if (listen(listenfd, -1) < 0)
112 err(-1, "stream_test: listen");
113
114 childpid = fork();
115 if (childpid < 0)
116 err(-1, "stream_test: fork");
117
118 if (childpid != 0) {
119 sleep(1);
120 stream_client();
121 kill(childpid, SIGTERM);
122 sleep(1);
123 } else
124 stream_server(listenfd);
125
126 (void)unlink(socket_path);
127 }
128
129 static void
datagram_server(int serverfd)130 datagram_server(int serverfd)
131 {
132 ssize_t len;
133 char c;
134
135 while (1) {
136 len = recv(serverfd, &c, sizeof(c), 0);
137 if (len < 0)
138 warn("datagram_server: recv");
139 }
140 }
141
142 static void
datagram_client(void)143 datagram_client(void)
144 {
145 struct sockaddr_un sun;
146 ssize_t len;
147 char c = 0;
148 int fd, i;
149
150 bzero(&sun, sizeof(sun));
151 sun.sun_len = sizeof(sun);
152 sun.sun_family = AF_UNIX;
153 strcpy(sun.sun_path, socket_path);
154 for (i = 0; i < ITERATIONS; i++) {
155 fd = socket(PF_UNIX, SOCK_DGRAM, 0);
156 if (fd < 0) {
157 warn("datagram_client: socket");
158 return;
159 }
160 len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun,
161 sizeof(sun));
162 if (len < 0)
163 warn("datagram_client: sendto");
164 close(fd);
165 }
166 }
167
168 static void
datagram_test(void)169 datagram_test(void)
170 {
171 struct sockaddr_un sun;
172 pid_t childpid;
173 int serverfd;
174
175 serverfd = socket(PF_UNIX, SOCK_DGRAM, 0);
176 if (serverfd < 0)
177 err(-1, "datagram_test: socket");
178
179 bzero(&sun, sizeof(sun));
180 sun.sun_len = sizeof(sun);
181 sun.sun_family = AF_UNIX;
182 strcpy(sun.sun_path, socket_path);
183
184 if (bind(serverfd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
185 err(-1, "datagram_test: bind");
186
187 childpid = fork();
188 if (childpid < 0)
189 err(-1, "datagram_test: fork");
190
191 if (childpid != 0) {
192 sleep(1);
193 datagram_client();
194 kill(childpid, SIGTERM);
195 sleep(1);
196 } else
197 datagram_server(serverfd);
198
199 (void)unlink(socket_path);
200 }
201
202 int
main(void)203 main(void)
204 {
205
206 if (mkstemp(socket_path) == -1)
207 err(1, "mkstemp failed");
208 (void)unlink(socket_path);
209 datagram_test();
210 if (0)
211 stream_test();
212 return (0);
213 }
214