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 78 static void 79 print(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 99 static int 100 acc(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; 133 fail: 134 if (s != -1) 135 close(s); 136 return -1; 137 } 138 139 static int 140 test(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; 249 fail: 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 263 ATF_TC(sockaddr_un_len_exceed); 264 ATF_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 272 ATF_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 278 ATF_TC(sockaddr_un_len_max); 279 ATF_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 287 ATF_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 293 ATF_TC(sockaddr_un_closed); 294 ATF_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 301 ATF_TC_BODY(sockaddr_un_closed, tc) 302 { 303 ATF_REQUIRE_MSG(test(true, 100) == 0, "test(true, 100): %s", 304 strerror(errno)); 305 } 306 307 ATF_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 316 int 317 main(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