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 * $FreeBSD$
27 */
28
29 /*
30 * Attempts to exercise UNIX domain socket races relating to the non-atomic
31 * connect-and-send properties of sendto(). As the result of such a race is
32 * a kernel panic, this test simply completes or doesn't.
33 *
34 * XXX: Despite implementing support for sendto() on stream sockets with
35 * implied connect, the appropriate flag isn't set in the FreeBSD kernel so
36 * it does not work. For now, don't call the stream test.
37 */
38
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/un.h>
42
43 #include <err.h>
44 #include <signal.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #define ITERATIONS 1000000
49
50 static char socket_path[] = "tmp.XXXXXX";
51
52 static void
stream_server(int listenfd)53 stream_server(int listenfd)
54 {
55 int acceptfd;
56
57 while (1) {
58 acceptfd = accept(listenfd, NULL, NULL);
59 if (acceptfd < 0) {
60 warn("stream_server: accept");
61 continue;
62 }
63 sleep(1);
64 close(acceptfd);
65 }
66 }
67
68 static void
stream_client(void)69 stream_client(void)
70 {
71 struct sockaddr_un sun;
72 ssize_t len;
73 char c = 0;
74 int fd, i;
75
76 bzero(&sun, sizeof(sun));
77 sun.sun_len = sizeof(sun);
78 sun.sun_family = AF_UNIX;
79 strcpy(sun.sun_path, socket_path);
80 for (i = 0; i < ITERATIONS; i++) {
81 fd = socket(PF_UNIX, SOCK_STREAM, 0);
82 if (fd < 0) {
83 warn("stream_client: socket");
84 return;
85 }
86 len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun,
87 sizeof(sun));
88 if (len < 0)
89 warn("stream_client: sendto");
90 close(fd);
91 }
92 }
93
94 static void
stream_test(void)95 stream_test(void)
96 {
97 struct sockaddr_un sun;
98 pid_t childpid;
99 int listenfd;
100
101 listenfd = socket(PF_UNIX, SOCK_STREAM, 0);
102 if (listenfd < 0)
103 err(-1, "stream_test: socket");
104
105 bzero(&sun, sizeof(sun));
106 sun.sun_len = sizeof(sun);
107 sun.sun_family = AF_UNIX;
108 strcpy(sun.sun_path, socket_path);
109
110 if (bind(listenfd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
111 err(-1, "stream_test: bind");
112
113 if (listen(listenfd, -1) < 0)
114 err(-1, "stream_test: listen");
115
116 childpid = fork();
117 if (childpid < 0)
118 err(-1, "stream_test: fork");
119
120 if (childpid != 0) {
121 sleep(1);
122 stream_client();
123 kill(childpid, SIGTERM);
124 sleep(1);
125 } else
126 stream_server(listenfd);
127
128 (void)unlink(socket_path);
129 }
130
131 static void
datagram_server(int serverfd)132 datagram_server(int serverfd)
133 {
134 ssize_t len;
135 char c;
136
137 while (1) {
138 len = recv(serverfd, &c, sizeof(c), 0);
139 if (len < 0)
140 warn("datagram_server: recv");
141 }
142 }
143
144 static void
datagram_client(void)145 datagram_client(void)
146 {
147 struct sockaddr_un sun;
148 ssize_t len;
149 char c = 0;
150 int fd, i;
151
152 bzero(&sun, sizeof(sun));
153 sun.sun_len = sizeof(sun);
154 sun.sun_family = AF_UNIX;
155 strcpy(sun.sun_path, socket_path);
156 for (i = 0; i < ITERATIONS; i++) {
157 fd = socket(PF_UNIX, SOCK_DGRAM, 0);
158 if (fd < 0) {
159 warn("datagram_client: socket");
160 return;
161 }
162 len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun,
163 sizeof(sun));
164 if (len < 0)
165 warn("datagram_client: sendto");
166 close(fd);
167 }
168 }
169
170 static void
datagram_test(void)171 datagram_test(void)
172 {
173 struct sockaddr_un sun;
174 pid_t childpid;
175 int serverfd;
176
177 serverfd = socket(PF_UNIX, SOCK_DGRAM, 0);
178 if (serverfd < 0)
179 err(-1, "datagram_test: socket");
180
181 bzero(&sun, sizeof(sun));
182 sun.sun_len = sizeof(sun);
183 sun.sun_family = AF_UNIX;
184 strcpy(sun.sun_path, socket_path);
185
186 if (bind(serverfd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
187 err(-1, "datagram_test: bind");
188
189 childpid = fork();
190 if (childpid < 0)
191 err(-1, "datagram_test: fork");
192
193 if (childpid != 0) {
194 sleep(1);
195 datagram_client();
196 kill(childpid, SIGTERM);
197 sleep(1);
198 } else
199 datagram_server(serverfd);
200
201 (void)unlink(socket_path);
202 }
203
204 int
main(void)205 main(void)
206 {
207
208 if (mkstemp(socket_path) == -1)
209 err(1, "mkstemp failed");
210 (void)unlink(socket_path);
211 datagram_test();
212 if (0)
213 stream_test();
214 return (0);
215 }
216