1/*	$NetBSD: t_unix.c,v 1.11 2013/11/13 21:41:23 christos Exp $	*/
2
3/*-
4 * Copyright (c) 2011 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *        This product includes software developed by the NetBSD
21 *        Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 *    contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39#include <sys/cdefs.h>
40#ifdef __RCSID
41__RCSID("$Id: t_unix.c,v 1.11 2013/11/13 21:41:23 christos Exp $");
42#else
43#define getprogname() argv[0]
44#endif
45
46#ifdef __linux__
47#define LX -1
48#else
49#define LX
50#endif
51#include <sys/param.h>
52#include <sys/socket.h>
53#include <sys/un.h>
54#include <stdio.h>
55#include <err.h>
56#include <errno.h>
57#include <string.h>
58#include <stddef.h>
59#include <stdlib.h>
60#include <unistd.h>
61#include <stdbool.h>
62
63#ifdef TEST
64#define FAIL(msg, ...)	err(EXIT_FAILURE, msg, ## __VA_ARGS__)
65#else
66
67#include <atf-c.h>
68#define FAIL(msg, ...)	\
69	do { \
70		ATF_CHECK_MSG(0, msg, ## __VA_ARGS__); \
71		goto fail; \
72	} while (/*CONSTCOND*/0)
73
74#endif
75
76#define OF offsetof(struct sockaddr_un, sun_path)
77
78static void
79print(const char *msg, struct sockaddr_un *addr, socklen_t len)
80{
81	size_t i;
82
83	printf("%s: client socket length: %zu\n", msg, (size_t)len);
84	printf("%s: client family %d\n", msg, addr->sun_family);
85#ifdef BSD4_4
86	printf("%s: client len %d\n", msg, addr->sun_len);
87#endif
88	printf("%s: socket name: ", msg);
89	for (i = 0; i < len - OF; i++) {
90		int ch = addr->sun_path[i];
91		if (ch < ' ' || '~' < ch)
92			printf("\\x%02x", ch);
93		else
94			printf("%c", ch);
95	}
96	printf("\n");
97}
98
99static int
100acc(int s)
101{
102	char guard1;
103	struct sockaddr_un sun;
104	char guard2;
105	socklen_t len;
106
107	guard1 = guard2 = 's';
108
109	memset(&sun, 0, sizeof(sun));
110	len = sizeof(sun);
111	if ((s = accept(s, (struct sockaddr *)&sun, &len)) == -1)
112		FAIL("accept");
113	if (guard1 != 's')
114		FAIL("guard1 = '%c'", guard1);
115	if (guard2 != 's')
116		FAIL("guard2 = '%c'", guard2);
117#ifdef DEBUG
118	print("accept", &sun, len);
119#endif
120	if (len != 2)
121		FAIL("len %d != 2", len);
122	if (sun.sun_family != AF_UNIX)
123		FAIL("sun->sun_family %d != AF_UNIX", sun.sun_family);
124#ifdef BSD4_4
125	if (sun.sun_len != 2)
126		FAIL("sun->sun_len %d != 2", sun.sun_len);
127#endif
128	for (size_t i = 0; i < sizeof(sun.sun_path); i++)
129		if (sun.sun_path[i])
130			FAIL("sun.sun_path[%zu] %d != NULL", i,
131			    sun.sun_path[i]);
132	return s;
133fail:
134	if (s != -1)
135		close(s);
136	return -1;
137}
138
139static int
140test(bool closeit, size_t len)
141{
142	size_t slen;
143	socklen_t sl;
144	int srvr = -1, clnt = -1, acpt = -1;
145	struct sockaddr_un *sock_addr = NULL, *sun = NULL;
146	socklen_t sock_addrlen;
147
148	srvr = socket(AF_UNIX, SOCK_STREAM, 0);
149	if (srvr == -1)
150		FAIL("socket(srvrer)");
151
152	slen = len + OF + 1;
153
154	if ((sun = calloc(1, slen)) == NULL)
155		FAIL("calloc");
156
157	srvr = socket(AF_UNIX, SOCK_STREAM, 0);
158	if (srvr == -1)
159		FAIL("socket");
160
161	memset(sun->sun_path, 'a', len);
162	sun->sun_path[len] = '\0';
163	(void)unlink(sun->sun_path);
164
165	sl = SUN_LEN(sun);
166#ifdef BSD4_4
167	sun->sun_len = sl;
168#endif
169	sun->sun_family = AF_UNIX;
170
171	if (bind(srvr, (struct sockaddr *)sun, sl) == -1) {
172		if (errno == EINVAL && sl >= 256) {
173			close(srvr);
174			return -1;
175		}
176		FAIL("bind");
177	}
178
179	if (listen(srvr, SOMAXCONN) == -1)
180		FAIL("listen");
181
182	clnt = socket(AF_UNIX, SOCK_STREAM, 0);
183	if (clnt == -1)
184		FAIL("socket(client)");
185
186	if (connect(clnt, (const struct sockaddr *)sun, sl) == -1)
187		FAIL("connect");
188
189	if (closeit) {
190		if (close(clnt) == -1)
191			FAIL("close");
192		clnt = -1;
193	}
194
195	acpt = acc(srvr);
196#if 0
197	/*
198	 * Both linux and NetBSD return ENOTCONN, why?
199	 */
200	if (!closeit) {
201		socklen_t peer_addrlen;
202		sockaddr_un peer_addr;
203
204		peer_addrlen = sizeof(peer_addr);
205		memset(&peer_addr, 0, sizeof(peer_addr));
206		if (getpeername(srvr, (struct sockaddr *)&peer_addr,
207		    &peer_addrlen) == -1)
208			FAIL("getpeername");
209		print("peer", &peer_addr, peer_addrlen);
210	}
211#endif
212
213	if ((sock_addr = calloc(1, slen)) == NULL)
214		FAIL("calloc");
215	sock_addrlen = slen;
216	if (getsockname(srvr, (struct sockaddr *)sock_addr, &sock_addrlen)
217	    == -1)
218		FAIL("getsockname");
219	print("sock", sock_addr, sock_addrlen);
220
221	if (sock_addr->sun_family != AF_UNIX)
222		FAIL("sock_addr->sun_family %d != AF_UNIX",
223		    sock_addr->sun_family);
224
225	len += OF;
226	if (sock_addrlen LX != len)
227		FAIL("sock_addr_len %zu != %zu", (size_t)sock_addrlen, len);
228#ifdef BSD4_4
229	if (sock_addr->sun_len != sl)
230		FAIL("sock_addr.sun_len %d != %zu", sock_addr->sun_len,
231		    (size_t)sl);
232#endif
233	for (size_t i = 0; i < slen - OF; i++)
234		if (sock_addr->sun_path[i] != sun->sun_path[i])
235			FAIL("sock_addr.sun_path[%zu] %d != "
236			    "sun->sun_path[%zu] %d\n", i,
237			    sock_addr->sun_path[i], i, sun->sun_path[i]);
238
239	if (acpt != -1)
240		(void)close(acpt);
241	if (srvr != -1)
242		(void)close(srvr);
243	if (clnt != -1 && !closeit)
244		(void)close(clnt);
245
246	free(sock_addr);
247	free(sun);
248	return 0;
249fail:
250	if (acpt != -1)
251		(void)close(acpt);
252	if (srvr != -1)
253		(void)close(srvr);
254	if (clnt != -1 && !closeit)
255		(void)close(clnt);
256	free(sock_addr);
257	free(sun);
258	return -1;
259}
260
261#ifndef TEST
262
263ATF_TC(sockaddr_un_len_exceed);
264ATF_TC_HEAD(sockaddr_un_len_exceed, tc)
265{
266
267	atf_tc_set_md_var(tc, "descr", "Check that exceeding the size of "
268	    "unix domain sockets does not trash memory or kernel when "
269	    "exceeding the size of the fixed sun_path");
270}
271
272ATF_TC_BODY(sockaddr_un_len_exceed, tc)
273{
274	ATF_REQUIRE_MSG(test(false, 254) == -1, "test(false, 254): %s",
275	    strerror(errno));
276}
277
278ATF_TC(sockaddr_un_len_max);
279ATF_TC_HEAD(sockaddr_un_len_max, tc)
280{
281
282	atf_tc_set_md_var(tc, "descr", "Check that we can use the maximum "
283	    "unix domain socket pathlen (253): 255 - sizeof(sun_len) - "
284	    "sizeof(sun_family)");
285}
286
287ATF_TC_BODY(sockaddr_un_len_max, tc)
288{
289	ATF_REQUIRE_MSG(test(false, 253) == 0, "test(false, 253): %s",
290	    strerror(errno));
291}
292
293ATF_TC(sockaddr_un_closed);
294ATF_TC_HEAD(sockaddr_un_closed, tc)
295{
296
297	atf_tc_set_md_var(tc, "descr", "Check that we can use the accepted "
298	    "address of unix domain socket when closed");
299}
300
301ATF_TC_BODY(sockaddr_un_closed, tc)
302{
303	ATF_REQUIRE_MSG(test(true, 100) == 0, "test(true, 100): %s",
304	    strerror(errno));
305}
306
307ATF_TP_ADD_TCS(tp)
308{
309
310	ATF_TP_ADD_TC(tp, sockaddr_un_len_exceed);
311	ATF_TP_ADD_TC(tp, sockaddr_un_len_max);
312	ATF_TP_ADD_TC(tp, sockaddr_un_closed);
313	return atf_no_error();
314}
315#else
316int
317main(int argc, char *argv[])
318{
319	size_t len;
320
321	if (argc == 1) {
322		fprintf(stderr, "Usage: %s <len>\n", getprogname());
323		return EXIT_FAILURE;
324	}
325	test(false, atoi(argv[1]));
326	test(true, atoi(argv[1]));
327}
328#endif
329