xref: /xnu-11417.101.15/tests/sioc-if-addr-bounds.c (revision e3723e1f17661b24996789d8afc084c0c3303b26)
1 /*
2  * Copyright (c) 2020-2022 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 /* -*- compile-command: "xcrun --sdk iphoneos.internal make sioc-if-addr-bounds" -*- */
30 
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <sys/sockio.h>
34 
35 #include <net/if.h>
36 #include <net/if_dl.h>
37 
38 #include <netinet/in.h>
39 #include <netinet/in_var.h>
40 
41 #include <string.h>
42 #include <unistd.h>
43 
44 #include <arpa/inet.h>
45 
46 #include <darwintest.h>
47 #include <darwintest_utils.h>
48 
49 #include <uuid/uuid.h>
50 
51 #include <ifaddrs.h>
52 
53 #include <arpa/inet.h>
54 
55 #include "ioc_str.h"
56 
57 T_GLOBAL_META(T_META_NAMESPACE("xnu.net"));
58 
59 #ifndef STRINGIFY
60 #define __STR(x)        #x              /* just a helper macro */
61 #define STRINGIFY(x)    __STR(x)
62 #endif /* STRINGIFY */
63 
64 #define IF_NAME       "bridge"
65 
66 /* On some platforms with DEBUG kernel, we need to wait a while */
67 #define SIFCREATE_RETRY 600
68 
69 #define PATTERN_SIZE 8
70 
71 static int
ifnet_destroy(int s,const char * ifname,bool fail_on_error)72 ifnet_destroy(int s, const char * ifname, bool fail_on_error)
73 {
74 	int             err;
75 	struct ifreq    ifr;
76 
77 	bzero(&ifr, sizeof(ifr));
78 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
79 	err = ioctl(s, SIOCIFDESTROY, &ifr);
80 	if (fail_on_error) {
81 		T_QUIET;
82 		T_ASSERT_POSIX_SUCCESS(err, "SIOCSIFDESTROY %s", ifr.ifr_name);
83 	}
84 	if (err < 0) {
85 		T_LOG("SIOCSIFDESTROY %s", ifr.ifr_name);
86 	}
87 	return err;
88 }
89 
90 static int
ifnet_set_flags(int s,const char * ifname,uint16_t flags_set,uint16_t flags_clear)91 ifnet_set_flags(int s, const char * ifname,
92     uint16_t flags_set, uint16_t flags_clear)
93 {
94 	uint16_t        flags_after;
95 	uint16_t        flags_before;
96 	struct ifreq    ifr;
97 	int             ret;
98 
99 	bzero(&ifr, sizeof(ifr));
100 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
101 	ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
102 	if (ret != 0) {
103 		T_LOG("SIOCGIFFLAGS %s", ifr.ifr_name);
104 		return ret;
105 	}
106 	flags_before = (uint16_t)ifr.ifr_flags;
107 	ifr.ifr_flags |= flags_set;
108 	ifr.ifr_flags &= ~(flags_clear);
109 	flags_after = (uint16_t)ifr.ifr_flags;
110 	if (flags_before == flags_after) {
111 		/* nothing to do */
112 		ret = 0;
113 	} else {
114 		/* issue the ioctl */
115 		T_QUIET;
116 		T_ASSERT_POSIX_SUCCESS(ioctl(s, SIOCSIFFLAGS, &ifr),
117 		    "SIOCSIFFLAGS %s 0x%x",
118 		    ifr.ifr_name, (uint16_t)ifr.ifr_flags);
119 	}
120 	return ret;
121 }
122 
123 static int
ifnet_create(int s,char * ifname,size_t ifname_size)124 ifnet_create(int s, char * ifname, size_t ifname_size)
125 {
126 	int error = 0;
127 	struct ifreq ifr;
128 
129 	bzero(&ifr, sizeof(ifr));
130 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
131 
132 	for (int i = 0; i < SIFCREATE_RETRY; i++) {
133 		if (ioctl(s, SIOCIFCREATE, &ifr) < 0) {
134 			error = errno;
135 			T_LOG("SIOCSIFCREATE %s: %s", ifname,
136 			    strerror(error));
137 			if (error == EBUSY) {
138 				/* interface is tearing down, try again */
139 				usleep(10000);
140 			} else if (error == EEXIST) {
141 				/* interface exists, try destroying it */
142 				(void)ifnet_destroy(s, ifname, false);
143 			} else {
144 				/* unexpected failure */
145 				break;
146 			}
147 		} else {
148 			error = 0;
149 			break;
150 		}
151 	}
152 	if (error == 0) {
153 		/* Copy back the interface name with unit number */
154 		strlcpy(ifname, ifr.ifr_name, ifname_size);
155 		error = ifnet_set_flags(s, ifname, IFF_UP, 0);
156 	}
157 	return error;
158 }
159 
160 #define MAXBUF 32
161 
162 static void
HexDump(void * data,size_t len)163 HexDump(void *data, size_t len)
164 {
165 	size_t i, j, k;
166 	unsigned char *ptr = (unsigned char *)data;
167 	unsigned char buf[3 * MAXBUF + 1];
168 
169 	for (i = 0; i < len; i += MAXBUF) {
170 		for (j = i, k = 0; j < i + MAXBUF && j < len; j++) {
171 			unsigned char msnbl = ptr[j] >> 4;
172 			unsigned char lsnbl = ptr[j] & 0x0f;
173 
174 			buf[k++] = msnbl < 10 ? msnbl + '0' : msnbl + 'a' - 10;
175 			buf[k++] = lsnbl < 10 ? lsnbl + '0' : lsnbl + 'a' - 10;
176 			if ((j % 2) == 1) {
177 				buf[k++] = ' ';
178 			}
179 			if ((j % MAXBUF) == MAXBUF - 1) {
180 				buf[k++] = ' ';
181 			}
182 		}
183 		buf[k] = 0;
184 		T_LOG("%5zd: %s\n", i, buf);
185 	}
186 }
187 
188 static size_t
snprint_dottedhex(char * str,size_t strsize,const void * data,const size_t datasize)189 snprint_dottedhex(char *str, size_t strsize, const void *data, const size_t datasize)
190 {
191 	size_t is = 0, ip = 0;
192 	const unsigned char *ptr = (const unsigned char *)data;
193 
194 	for (is = 0, ip = 0; is + 3 < strsize - 1 && ip < datasize; ip++) {
195 		unsigned char msnbl = ptr[ip] >> 4;
196 		unsigned char lsnbl = ptr[ip] & 0x0f;
197 
198 		if (ip > 0) {
199 			str[is++] = '.';
200 		}
201 		str[is++] = (char)(msnbl + (msnbl < 10 ? '0' : 'a' - 10));
202 		str[is++] = (char)(lsnbl + (lsnbl < 10 ? '0' : 'a' - 10));
203 	}
204 	str[is] = 0;
205 	return is;
206 }
207 
208 static void
print_sockaddr_dl(const char * pre,const struct sockaddr * sa,const char * post)209 print_sockaddr_dl(const char *pre, const struct sockaddr *sa, const char *post)
210 {
211 	char nbuffer[256];
212 	char abuffer[256];
213 	char sbuffer[256];
214 	struct sockaddr_dl sdl = { 0 };
215 
216 	if (sa == NULL) {
217 		return;
218 	}
219 	memcpy(&sdl, sa, MIN(sizeof(sdl), sa->sa_len));
220 	strlcpy(nbuffer, sdl.sdl_data, sdl.sdl_nlen);
221 	snprint_dottedhex(abuffer, sizeof(abuffer), sdl.sdl_data + sdl.sdl_nlen, sdl.sdl_alen);
222 	snprint_dottedhex(sbuffer, sizeof(sbuffer), sdl.sdl_data + sdl.sdl_nlen + sdl.sdl_alen, sdl.sdl_slen);
223 
224 	T_LOG("%ssdl_len %u sdl_family %u sdl_index %u sdl_type %u sdl_nlen %u (%s) sdl_alen %u (%s) sdl_slen %u (%s)%s",
225 	    pre != NULL ? pre : "",
226 	    sdl.sdl_len, sdl.sdl_family, sdl.sdl_index, sdl.sdl_type,
227 	    sdl.sdl_nlen, nbuffer, sdl.sdl_alen, abuffer, sdl.sdl_slen, sbuffer,
228 	    post != NULL ? post : "");
229 }
230 
231 static void
print_sockaddr_in(const char * pre,const struct sockaddr * sa,const char * post)232 print_sockaddr_in(const char *pre, const struct sockaddr *sa, const char *post)
233 {
234 	char abuffer[256];
235 	char zbuffer[256];
236 	struct sockaddr_in sin = { 0 };
237 
238 	if (sa == NULL) {
239 		return;
240 	}
241 
242 	memcpy(&sin, sa, MIN(sizeof(sin), sa->sa_len));
243 	inet_ntop(AF_INET, &sin.sin_addr, abuffer, sizeof(abuffer));
244 	snprint_dottedhex(zbuffer, sizeof(zbuffer), sin.sin_zero, sizeof(sin.sin_zero));
245 
246 	T_LOG("%ssin_len %u sin_family %u sin_port %u sin_addr %s sin_zero %s%s",
247 	    pre != NULL ? pre : "",
248 	    sin.sin_len, sin.sin_family, htons(sin.sin_port), abuffer, zbuffer,
249 	    post != NULL ? post : "");
250 }
251 
252 static void
print_sockaddr_in6(const char * pre,const struct sockaddr * sa,const char * post)253 print_sockaddr_in6(const char *pre, const struct sockaddr *sa, const char *post)
254 {
255 	char abuffer[256];
256 	struct sockaddr_in6 sin6 = { 0 };
257 
258 	if (sa == NULL) {
259 		return;
260 	}
261 
262 	memcpy(&sin6, sa, MIN(sizeof(sin6), sa->sa_len));
263 	inet_ntop(AF_INET6, &sin6.sin6_addr, abuffer, sizeof(abuffer));
264 
265 	T_LOG("%ssin6_len %u sin6_family %u sin6_port %u sin6_flowinfo %u sin6_addr %s sin6_scope_id %u%s",
266 	    pre != NULL ? pre : "",
267 	    sin6.sin6_len, sin6.sin6_family, htons(sin6.sin6_port), sin6.sin6_flowinfo, abuffer, sin6.sin6_scope_id,
268 	    post != NULL ? post : "");
269 }
270 
271 static void
print_sockaddr(const char * pre,const struct sockaddr * sa,const char * post)272 print_sockaddr(const char *pre, const struct sockaddr *sa, const char *post)
273 {
274 	char buffer[256];
275 
276 	if (sa == NULL) {
277 		return;
278 	}
279 
280 	snprint_dottedhex(buffer, sizeof(buffer), sa->sa_data, sa->sa_len - 2);
281 
282 	T_LOG("%ssa_len %u sa_family %u sa_data %s%s",
283 	    pre != NULL ? pre : "",
284 	    sa->sa_len, sa->sa_family, buffer,
285 	    post != NULL ? post : "");
286 }
287 
288 
289 #define ROUNDUP(a, size) (((a) & ((size) - 1)) ? (1 + ((a)|(size - 1))) : (a))
290 
291 #define NEXT_SA(p) (struct sockaddr *) \
292     ((caddr_t)p + (p->sa_len ? ROUNDUP(p->sa_len, sizeof(u_int32_t)) : \
293      sizeof(u_long)))
294 
295 static size_t
get_rti_info(int addrs,struct sockaddr * sa,struct sockaddr ** rti_info)296 get_rti_info(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
297 {
298 	int i;
299 	size_t len = 0;
300 
301 	for (i = 0; i < RTAX_MAX; i++) {
302 		if (addrs & (1 << i)) {
303 			rti_info[i] = sa;
304 			if (sa->sa_len < sizeof(struct sockaddr)) {
305 				len += sizeof(struct sockaddr);
306 			} else {
307 				len += sa->sa_len;
308 			}
309 			sa = NEXT_SA(sa);
310 		} else {
311 			rti_info[i] = NULL;
312 		}
313 	}
314 	return len;
315 }
316 
317 static void
print_address(const char * pre,const struct sockaddr * sa,const char * post,u_char asFamily)318 print_address(const char *pre, const struct sockaddr *sa, const char *post, u_char asFamily)
319 {
320 	if (sa == NULL) {
321 		T_LOG("%s(NULL)%s",
322 		    pre != NULL ? pre : "",
323 		    post != NULL ? post : "");
324 		return;
325 	}
326 	if (sa->sa_len == 0) {
327 		T_LOG("%ssa_len 0%s",
328 		    pre != NULL ? pre : "",
329 		    post != NULL ? post : "");
330 		return;
331 	}
332 	if (sa->sa_len == 1) {
333 		T_LOG("%ssa_len 1%s",
334 		    pre != NULL ? pre : "",
335 		    post != NULL ? post : "");
336 		return;
337 	}
338 
339 	// If not forced
340 	if (asFamily == AF_UNSPEC) {
341 		asFamily = sa->sa_family;
342 	}
343 	switch (asFamily) {
344 	case AF_INET: {
345 		print_sockaddr_in(pre, sa, post);
346 		break;
347 	}
348 	case AF_INET6: {
349 		print_sockaddr_in6(pre, sa, post);
350 		break;
351 	}
352 	case AF_LINK: {
353 		print_sockaddr_dl(pre, sa, post);
354 		break;
355 	}
356 	default:
357 		print_sockaddr(pre, sa, post);
358 		break;
359 	}
360 }
361 
362 static void
print_rti_info(struct sockaddr * rti_info[])363 print_rti_info(struct sockaddr *rti_info[])
364 {
365 	struct sockaddr *sa;
366 	u_char asFamily = 0;
367 
368 	if ((sa = rti_info[RTAX_IFA])) {
369 		asFamily = sa->sa_family;
370 		print_address(" RTAX_IFA         ", sa, "\n", 0);
371 	}
372 	if ((sa = rti_info[RTAX_DST])) {
373 		asFamily = sa->sa_family;
374 		print_address(" RTAX_DST         ", sa, "\n", 0);
375 	}
376 	if ((sa = rti_info[RTAX_BRD])) {
377 		print_address(" RTAX_BRD         ", sa, "\n", asFamily);
378 	}
379 
380 	if ((sa = rti_info[RTAX_NETMASK])) {
381 		print_address(" RTAX_NETMASK     ", sa, "\n", asFamily);
382 	}
383 
384 	if ((sa = rti_info[RTAX_GATEWAY])) {
385 		print_address(" RTAX_GATEWAY     ", sa, "\n", 0);
386 	}
387 
388 	if ((sa = rti_info[RTAX_GENMASK])) {
389 		print_address(" RTAX_GENMASK     ", sa, "\n", asFamily);
390 	}
391 
392 	if ((sa = rti_info[RTAX_AUTHOR])) {
393 		print_address(" RTAX_AUTHOR      ", sa, "\n", asFamily);
394 	}
395 
396 	if ((sa = rti_info[RTAX_IFP])) {
397 		print_address(" RTAX_IFP         ", sa, "\n", 0);
398 	}
399 }
400 
401 static void
print_rt_iflist2(const char * label)402 print_rt_iflist2(const char *label)
403 {
404 	size_t len;
405 	int mib[6] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0 };
406 	unsigned char *buf = NULL;
407 	unsigned char *lim, *next;
408 	struct if_msghdr *ifmsg;
409 
410 	T_LOG("interface address list for %s", label);
411 
412 	T_QUIET; T_EXPECT_POSIX_SUCCESS(sysctl(mib, 6, NULL, &len, NULL, 0), "sysctl NET_RT_IFLIST2");
413 
414 	T_QUIET; T_ASSERT_NOTNULL(buf = calloc(1, len), "rt_if_list_buf calloc(1, %zd)", len);
415 
416 	T_QUIET; T_EXPECT_POSIX_SUCCESS(sysctl(mib, 6, buf, &len, NULL, 0), "sysctl NET_RT_IFLIST2");
417 
418 	lim = buf + len;
419 	for (next = buf; next < lim; next += ifmsg->ifm_msglen) {
420 		ifmsg = (struct if_msghdr *)(void *)next;
421 		char ifname[IF_NAMESIZE + 1];
422 
423 		if (ifmsg->ifm_type == RTM_IFINFO2) {
424 			struct if_msghdr2 *ifm = (struct if_msghdr2 *)ifmsg;
425 			struct sockaddr *sa = (struct sockaddr *)(ifm + 1);
426 
427 			(void)if_indextoname(ifm->ifm_index, ifname);
428 			T_LOG("interface: %s", ifname);
429 			print_address(" PRIMARY          ", sa, "", 0);
430 		} else if (ifmsg->ifm_type == RTM_NEWADDR) {
431 			struct sockaddr *rti_info[RTAX_MAX];
432 			struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifmsg;
433 
434 			(void) get_rti_info(ifam->ifam_addrs, (struct sockaddr *)(ifam + 1), rti_info);
435 
436 			print_rti_info(rti_info);
437 		}
438 	}
439 	free(buf);
440 }
441 
442 static int
check_rt_if_list_for_pattern(const char * label,unsigned char pattern,size_t pattern_size)443 check_rt_if_list_for_pattern(const char *label, unsigned char pattern, size_t pattern_size)
444 {
445 	size_t i;
446 	size_t len;
447 	int mib[6] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
448 	unsigned char *rt_if_list_buf = NULL;
449 	int count = 0;
450 	unsigned char *pattern_buf = NULL;
451 
452 	T_QUIET; T_ASSERT_NOTNULL(pattern_buf = calloc(1, pattern_size), "pattern_buf calloc(1, %zd)", pattern_size);
453 	memset(pattern_buf, pattern, pattern_size);
454 
455 	T_QUIET; T_EXPECT_POSIX_SUCCESS(sysctl(mib, 6, NULL, &len, NULL, 0), "sysctl NET_RT_IFLIST");
456 
457 	T_QUIET; T_ASSERT_NOTNULL(rt_if_list_buf = calloc(1, len), "rt_if_list_buf calloc(1, %zd)", len);
458 
459 	T_QUIET; T_EXPECT_POSIX_SUCCESS(sysctl(mib, 6, rt_if_list_buf, &len, NULL, 0), "sysctl NET_RT_IFLIST");
460 
461 	if (label != NULL) {
462 		T_LOG("%s sysctl NET_RT_IFLIST buffer length %zd\n", label, len);
463 	}
464 
465 	count = 0;
466 	for (i = 0; i < len - pattern_size; i++) {
467 		if (memcmp(rt_if_list_buf + i, pattern_buf, pattern_size) == 0) {
468 			count++;
469 			i += pattern_size - 1;
470 		}
471 	}
472 
473 	if (label != NULL) {
474 		if (label != NULL && count > 0) {
475 			T_LOG("%s found pattern at %zd count %d times\n", label, i, count);
476 			HexDump(rt_if_list_buf, len);
477 		}
478 	}
479 
480 	free(rt_if_list_buf);
481 	free(pattern_buf);
482 
483 	return count;
484 }
485 
486 static bool
find_unused_pattern_in_rt_if_list(unsigned char * pattern,size_t pattern_size)487 find_unused_pattern_in_rt_if_list(unsigned char *pattern, size_t pattern_size)
488 {
489 	bool found_pattern = false;
490 	unsigned char i;
491 	unsigned char *pattern_buf = NULL;
492 
493 	T_QUIET; T_ASSERT_NOTNULL(pattern_buf = calloc(1, pattern_size), "pattern_buf calloc(1, %zd)", pattern_size);
494 
495 	/* Try 10 times to find an unused pattern */
496 	for (i = 1; i < 255; i++) {
497 		if (check_rt_if_list_for_pattern(NULL, i, pattern_size) == 0) {
498 			found_pattern = true;
499 			*pattern = i;
500 			memset(pattern_buf, i, pattern_size);
501 			T_LOG("PATTERN: ");
502 			HexDump(pattern_buf, pattern_size);
503 			break;
504 		}
505 	}
506 	free(pattern_buf);
507 
508 	return found_pattern;
509 }
510 
511 static const char *
ioc_str(unsigned long cmd)512 ioc_str(unsigned long cmd)
513 {
514 	switch (cmd) {
515 #define X(a) case a: return #a;
516 		SIOC_LIST
517 #undef X
518 	default:
519 		break;
520 	}
521 	return "";
522 }
523 
524 struct ioc_ifreq {
525 	unsigned long ioc_cmd;
526 	uint8_t salen;
527 	uint8_t safamily;
528 	const char *sastr;
529 	int error; // 0 means no error, -1, end of list, otherwise expected errno
530 };
531 
532 static struct ioc_ifreq ioc_list[] = {
533 	{ SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET6, "10.2.3.1", EINVAL },
534 	{ SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET6, "10.2.3.1", EADDRNOTAVAIL },
535 	{ SIOCDIFADDR, sizeof(struct sockaddr_in6), AF_INET, "10.2.3.1", EADDRNOTAVAIL },
536 	{ SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.1", EADDRNOTAVAIL },
537 
538 	{ SIOCSIFADDR, 0xf0, AF_INET6, "10.2.3.1", EINVAL },
539 	{ SIOCDIFADDR, 0xf0, AF_INET6, "10.2.3.1", EADDRNOTAVAIL },
540 	{ SIOCDIFADDR, 0xf0, AF_INET, "10.2.3.1", EADDRNOTAVAIL },
541 	{ SIOCDIFADDR, 0xf0, AF_INET, "10.2.3.1", EADDRNOTAVAIL },
542 
543 	{ SIOCSIFADDR, 0, AF_INET6, "10.2.3.1", EINVAL },
544 	{ SIOCDIFADDR, 0, AF_INET6, "10.2.3.1", EADDRNOTAVAIL },
545 	{ SIOCDIFADDR, 0, AF_INET, "10.2.3.1", EADDRNOTAVAIL },
546 	{ SIOCDIFADDR, 0, AF_INET, "10.2.3.1", EADDRNOTAVAIL },
547 
548 	{ SIOCSIFADDR, sizeof(struct sockaddr_in6), AF_INET, "10.2.3.2", 0 },
549 	{ SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET6, "10.2.3.2", 0 },
550 
551 	{ SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.3", 0 },
552 	{ SIOCDIFADDR, sizeof(struct sockaddr_in6), AF_INET, "10.2.3.3", 0 },
553 
554 	{ SIOCSIFADDR, sizeof(struct sockaddr_in6), AF_INET6, "10.2.3.4", EINVAL },
555 	{ SIOCDIFADDR, sizeof(struct sockaddr_in6), AF_INET, "10.2.3.4", EADDRNOTAVAIL },
556 
557 	{ SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.5", 0 },
558 	{ SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET, "0.0.0.0", EADDRNOTAVAIL },
559 	{ SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.5", 0 },
560 
561 	{ SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.6", 0 },
562 
563 	{ SIOCSIFNETMASK, sizeof(struct sockaddr_in), 0, "ff.00.00.00", 0 },
564 	{ SIOCSIFNETMASK, sizeof(struct sockaddr_in), AF_INET, "ff.00.00.00", 0 },
565 	{ SIOCSIFNETMASK, sizeof(struct sockaddr_in), AF_INET6, "ff.f.00.00", 0 },
566 
567 	{ SIOCSIFNETMASK, sizeof(struct sockaddr_in6), 0, "ff.ff.00.00", 0 },
568 	{ SIOCSIFNETMASK, sizeof(struct sockaddr_in6), AF_INET, "ff.ff.00.00", 0 },
569 	{ SIOCSIFNETMASK, sizeof(struct sockaddr_in6), AF_INET6, "ff.ff.f0.00", 0 },
570 
571 	{ SIOCSIFNETMASK, 0, 0, "ff.ff.00.00", 0 },
572 	{ SIOCSIFNETMASK, 0, AF_INET, "ff.ff.00.00", 0 },
573 	{ SIOCSIFNETMASK, 0, AF_INET6, "ff.ff.f0.00", 0 },
574 
575 	{ SIOCSIFNETMASK, 0xf0, 0, "ff.ff.00.00", 0 },
576 	{ SIOCSIFNETMASK, 0xf0, AF_INET, "ff.ff.00.00", 0 },
577 	{ SIOCSIFNETMASK, 0xf0, AF_INET6, "ff.ff.f0.00", 0 },
578 
579 	{ SIOCSIFBRDADDR, sizeof(struct sockaddr_in), 0, "10.255.255.255", 0 },
580 	{ SIOCSIFBRDADDR, sizeof(struct sockaddr_in), AF_INET, "10.255.255.255", 0 },
581 	{ SIOCSIFBRDADDR, sizeof(struct sockaddr_in), AF_INET6, "10.255.255.255", 0 },
582 	{ SIOCSIFBRDADDR, sizeof(struct sockaddr_in6), AF_INET, "10.255.255.255", 0 },
583 
584 	{ SIOCSIFBRDADDR, 0xf0, 0, "10.255.255.255", 0 },
585 	{ SIOCSIFBRDADDR, 0xf0, AF_INET, "10.255.255.255", 0 },
586 	{ SIOCSIFBRDADDR, 0xf0, AF_INET6, "10.255.255.255", 0 },
587 	{ SIOCSIFBRDADDR, 0xf0, AF_INET, "10.255.255.255", 0 },
588 
589 	{ SIOCSIFBRDADDR, 0, 0, "10.255.255.255", 0 },
590 	{ SIOCSIFBRDADDR, 0, AF_INET, "10.255.255.255", 0 },
591 	{ SIOCSIFBRDADDR, 0, AF_INET6, "10.255.255.255", 0 },
592 	{ SIOCSIFBRDADDR, 0, AF_INET, "10.255.255.255", 0 },
593 
594 	{ 0, 0, 0, "", -1 },
595 };
596 
597 static void
test_sioc_ifr_bounds(struct ioc_ifreq * ioc_ifreq,int s,const char * ifname)598 test_sioc_ifr_bounds(struct ioc_ifreq *ioc_ifreq, int s, const char *ifname)
599 {
600 	struct ifreq ifr = { 0 };
601 	unsigned char pattern;
602 	struct sockaddr_in *sin;
603 
604 	T_LOG("");
605 	T_LOG("TEST CASE: %s ioctl(%s, sa_len %u, sa_family %u, %s) -> %d", __func__,
606 	    ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->salen, ioc_ifreq->safamily, ioc_ifreq->sastr, ioc_ifreq->error);
607 
608 
609 	if (find_unused_pattern_in_rt_if_list(&pattern, PATTERN_SIZE) == false) {
610 		T_SKIP("Could not find unused pattern");
611 	}
612 
613 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
614 	memset(&ifr.ifr_addr.sa_data, pattern, sizeof(ifr.ifr_dstaddr.sa_data));
615 
616 	sin = (struct sockaddr_in *)(void *)&ifr.ifr_addr;
617 	sin->sin_len = ioc_ifreq->salen;
618 	sin->sin_family = ioc_ifreq->safamily;
619 	sin->sin_addr.s_addr = inet_addr(ioc_ifreq->sastr);
620 
621 	int retval;
622 	if (ioc_ifreq->error == 0) {
623 		T_EXPECT_POSIX_SUCCESS(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifr),
624 		    "%s, %s: retval %d", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval);
625 	} else {
626 		T_EXPECT_POSIX_FAILURE(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifr), ioc_ifreq->error,
627 		    "%s, %s: retval %d errno %s", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval, strerror(errno));
628 	}
629 
630 	T_EXPECT_EQ(check_rt_if_list_for_pattern("test_sioc_ifr_bounds", pattern, PATTERN_SIZE), 0, "pattern should not be found");
631 
632 
633 	fflush(stdout);
634 	fflush(stderr);
635 }
636 
637 T_DECL(sioc_ifr_bounds, "test bound checks on struct ifreq addresses passed to interface ioctls",
638     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
639 {
640 	int s = -1;
641 	char ifname[IFNAMSIZ];
642 
643 	T_LOG("%s", __func__);
644 
645 	T_QUIET; T_EXPECT_POSIX_SUCCESS(s = socket(AF_INET, SOCK_DGRAM, 0), "socket");
646 
647 	strlcpy(ifname, IF_NAME, sizeof(ifname));
648 
649 	int error = 0;
650 	if ((error = ifnet_create(s, ifname, sizeof(ifname))) != 0) {
651 		if (error == EINVAL) {
652 			T_SKIP("The system does not support the %s cloning interface", IF_NAME);
653 		}
654 		T_SKIP("This test failed creating a %s cloning interface", IF_NAME);
655 	}
656 	T_LOG("created clone interface '%s'", ifname);
657 
658 	struct ioc_ifreq *ioc_ifreq;
659 	for (ioc_ifreq = ioc_list; ioc_ifreq->error != -1; ioc_ifreq++) {
660 		test_sioc_ifr_bounds(ioc_ifreq, s, ifname);
661 	}
662 	print_rt_iflist2(__func__);
663 	(void)ifnet_destroy(s, ifname, true);
664 
665 	close(s);
666 }
667 
668 struct ioc_ifra {
669 	const char *description;
670 
671 	uint8_t addr_len;
672 	uint8_t addr_fam;
673 	const char *addr_str;
674 
675 	uint8_t broad_len;
676 	uint8_t broad_fam;
677 	const char *broad_str;
678 
679 	uint8_t mask_len;
680 	uint8_t mask_fam;
681 	const char *mask_str;
682 
683 	int error; // 0 means no error, -1, end of list, otherwise expected errno
684 };
685 
686 static struct ioc_ifra ioc_ifra_list[] = {
687 	{
688 		.description = "fully formed",
689 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.1.1.1",
690 		.broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "1.1.1.255",
691 		.mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.255.0.0",
692 		.error = 0
693 	},
694 	{
695 		.description = "addr_len 0",
696 		.addr_len = 0, .addr_fam = AF_INET, .addr_str = "10.2.2.0",
697 		.broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.2.2.255",
698 		.mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.0.0.0",
699 		.error = 0
700 	},
701 	{
702 		.description = "addr_len 1",
703 		.addr_len = 1, .addr_fam = AF_INET, .addr_str = "10.2.2.1",
704 		.broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.2.2.255",
705 		.mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.0.0.0",
706 		.error = 0
707 	},
708 	{
709 		.description = "addr_len 250",
710 		.addr_len = 250, .addr_fam = AF_INET, .addr_str = "10.2.2.250",
711 		.broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.2.2.255",
712 		.mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.0.0.0",
713 		.error = 0
714 	},
715 	{
716 		.description = "addr_family AF_INET6",
717 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET6, .addr_str = "10.3.3.3",
718 		.broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.3.255.255",
719 		.mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.255.255.0",
720 		.error = EINVAL
721 	},
722 	{
723 		.description = "broadcast_len 0xf0",
724 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.4.4.4",
725 		.broad_len = 0xf0, .broad_fam = AF_INET, .broad_str = "10.4.4.255",
726 		.mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.255.255.0",
727 		.error = 0
728 	},
729 	{
730 		.description = "broadcast_family AF_INET6",
731 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.5.5.5",
732 		.broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET6, .broad_str = "10.5.5.255",
733 		.mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.255.0.0",
734 		.error = 0
735 	},
736 	{
737 		.description = "mask_len 0xf0",
738 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.6.6.6",
739 		.broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "1.6.6.255",
740 		.mask_len = 0xf0, .mask_fam = AF_INET, .mask_str = "255.255.0.0",
741 		.error = 0
742 	},
743 	{
744 		.description = "mask_family AF_INET6",
745 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.7.7.7",
746 		.broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.7.7.255",
747 		.mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET6, .mask_str = "255.255.0.0",
748 		.error = 0
749 	},
750 	{
751 		.description = "ifra address only",
752 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.8.8.8",
753 		.broad_len = 0, .broad_str = NULL,
754 		.mask_len = 0, .mask_str = NULL,
755 		.error = 0
756 	},
757 	{
758 		.description = "ifra mask len 1",
759 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.1",
760 		.broad_len = 0, .broad_str = NULL,
761 		.mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
762 		.error = 0
763 	},
764 	{
765 		.description = "ifra mask len 3",
766 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.3",
767 		.broad_len = 0, .broad_str = NULL,
768 		.mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
769 		.error = 0
770 	},
771 	{
772 		.description = "ifra mask len 5",
773 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.5",
774 		.broad_len = 0, .broad_str = NULL,
775 		.mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
776 		.error = 0
777 	},
778 	{
779 		.description = "ifra mask len 7",
780 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.7",
781 		.broad_len = 0, .broad_str = NULL,
782 		.mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
783 		.error = 0
784 	},
785 	{
786 		.description = "ifra mask len 9",
787 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.9",
788 		.broad_len = 0, .broad_str = NULL,
789 		.mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
790 		.error = 0
791 	},
792 	{
793 		.description = "ifra mask len 11",
794 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.11",
795 		.broad_len = 0, .broad_str = NULL,
796 		.mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
797 		.error = 0
798 	},
799 	{
800 		.description = "ifra mask len 13",
801 		.addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.13",
802 		.broad_len = 0, .broad_str = NULL,
803 		.mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
804 		.error = 0
805 	},
806 	{
807 		.description = NULL,
808 		.error = -1
809 	}
810 };
811 
812 T_DECL(sioc_ifra_addr_bounds, "test bound checks on socket address passed to interface ioctls",
813     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
814 {
815 	int s = -1;
816 
817 	T_QUIET; T_EXPECT_POSIX_SUCCESS(s = socket(AF_INET, SOCK_DGRAM, 0), "socket");
818 
819 	char ifname[IFNAMSIZ];
820 	strlcpy(ifname, IF_NAME, sizeof(ifname));
821 	int error = 0;
822 	if ((error = ifnet_create(s, ifname, sizeof(ifname))) != 0) {
823 		if (error == EINVAL) {
824 			T_SKIP("The system does not support the %s cloning interface", IF_NAME);
825 		}
826 		T_SKIP("This test failed creating a %s cloning interface", IF_NAME);
827 	}
828 	T_LOG("created clone interface '%s'", ifname);
829 
830 	struct ioc_ifra *ioc_ifra;
831 
832 	for (ioc_ifra = ioc_ifra_list; ioc_ifra->error != -1; ioc_ifra++) {
833 		struct in_aliasreq ifra = { 0 };
834 		unsigned char pattern;
835 		int retval;
836 
837 		T_LOG("");
838 		T_LOG("TEST CASE: %s, ioctl(SIOCAIFADDR, %s)", ioc_ifra->description, ioc_ifra->addr_str != NULL ? ioc_ifra->addr_str : "");
839 
840 		if (find_unused_pattern_in_rt_if_list(&pattern, PATTERN_SIZE) == false) {
841 			T_SKIP("Could not find unused pattern in rt_if_list");
842 			return;
843 		}
844 
845 		memset(&ifra, pattern, sizeof(ifra));
846 
847 		strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
848 
849 		ifra.ifra_addr.sin_len = ioc_ifra->addr_len;
850 		ifra.ifra_addr.sin_family = ioc_ifra->addr_fam;
851 		if (ioc_ifra->addr_str != NULL) {
852 			ifra.ifra_addr.sin_addr.s_addr = inet_addr(ioc_ifra->addr_str);
853 		}
854 
855 		ifra.ifra_broadaddr.sin_len = ioc_ifra->broad_len;
856 		ifra.ifra_broadaddr.sin_family = ioc_ifra->broad_fam;
857 		if (ioc_ifra->broad_str != NULL) {
858 			ifra.ifra_broadaddr.sin_addr.s_addr = inet_addr(ioc_ifra->broad_str);
859 		}
860 
861 		ifra.ifra_mask.sin_len = ioc_ifra->mask_len;
862 		ifra.ifra_mask.sin_family = ioc_ifra->mask_fam;
863 		if (ioc_ifra->mask_str != NULL) {
864 			ifra.ifra_mask.sin_addr.s_addr = inet_addr(ioc_ifra->mask_str);
865 		}
866 
867 		if (ioc_ifra->error == 0) {
868 			T_EXPECT_POSIX_SUCCESS(retval = ioctl(s, SIOCAIFADDR, &ifra), "SIOCAIFADDR retval %d", retval);
869 		} else {
870 			T_EXPECT_POSIX_FAILURE(retval = ioctl(s, SIOCAIFADDR, &ifra), EINVAL, "SIOCAIFADDR retval %d, %s", retval, strerror(errno));
871 		}
872 
873 		T_EXPECT_EQ(check_rt_if_list_for_pattern("after ioctl SIOCAIFADDR", pattern, PATTERN_SIZE), 0, "pattern should not be found");
874 	}
875 
876 	print_rt_iflist2(__func__);
877 
878 	(void)ifnet_destroy(s, ifname, true);
879 
880 	close(s);
881 }
882 
883 T_DECL(sioc_ifr_dstaddr_leak, "test bound checks on socket address passed to interface ioctls",
884     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
885 {
886 	int s = -1;
887 	struct ifreq ifr = { 0 };
888 	unsigned char pattern;
889 	struct ifaddrs *ifap = NULL, *ifa;
890 	bool found_gif0 = false;
891 
892 	T_QUIET; T_EXPECT_POSIX_SUCCESS(getifaddrs(&ifap), "getifaddrs");
893 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
894 		if (strcmp(ifa->ifa_name, "gif0") == 0) {
895 			found_gif0 = true;
896 			break;
897 		}
898 	}
899 	freeifaddrs(ifap);
900 	ifap = NULL;
901 	if (found_gif0 == false) {
902 		T_SKIP("gif0 does not exists");
903 	}
904 
905 	if (find_unused_pattern_in_rt_if_list(&pattern, PATTERN_SIZE) == false) {
906 		T_SKIP("Could not find unused pattern");
907 		return;
908 	}
909 
910 	T_QUIET; T_EXPECT_POSIX_SUCCESS(s = socket(AF_INET, SOCK_DGRAM, 0), "socket");
911 
912 	strlcpy(ifr.ifr_name, "gif0", sizeof(ifr.ifr_name));
913 	ifr.ifr_dstaddr.sa_family = AF_INET6;
914 	ifr.ifr_dstaddr.sa_len = 0xf0;
915 	memset(&ifr.ifr_dstaddr.sa_data, pattern, PATTERN_SIZE);
916 
917 	T_EXPECT_POSIX_SUCCESS(ioctl(s, SIOCSIFDSTADDR, &ifr), "ioctl(SIOCSIFDSTADDR)");
918 
919 	print_rt_iflist2(__func__);
920 
921 	close(s);
922 
923 	T_EXPECT_EQ(check_rt_if_list_for_pattern("AFTER", pattern, PATTERN_SIZE), 0, "pattern should not be found");
924 }
925 
926 static struct ioc_ifreq ioc_list_config[] = {
927 	{ SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "0.0.0.0", EINVAL },
928 	{ SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "255.255.255.255", EINVAL },
929 	{ SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "238.207.49.91", EINVAL },
930 
931 	{ SIOCAIFADDR_IN6, sizeof(struct sockaddr_in6), AF_INET6, "::", EINVAL },
932 	{ SIOCAIFADDR_IN6, sizeof(struct sockaddr_in6), AF_INET6, "ff33:40:fd25:549c:675b::1", EINVAL },
933 	{ SIOCAIFADDR_IN6, sizeof(struct sockaddr_in6), AF_INET6, "::ffff:0a0a:0a0a", EINVAL },
934 	{ SIOCAIFADDR_IN6, sizeof(struct sockaddr_in6), AF_INET6, "::0a0a:0a0a", EINVAL },
935 
936 	{ 0, 0, 0, "", -1 },
937 };
938 
939 static void
test_sioc_ifr_addr_config_v4(struct ioc_ifreq * ioc_ifreq,int s,const char * ifname)940 test_sioc_ifr_addr_config_v4(struct ioc_ifreq *ioc_ifreq, int s, const char *ifname)
941 {
942 	struct ifreq ifr = { 0 };
943 	struct sockaddr_in *sin;
944 
945 	T_LOG("");
946 	T_LOG("TEST CASE: %s ioctl(%s, sa_len %u, sa_family %u, %s) -> %d", __func__,
947 	    ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->salen, ioc_ifreq->safamily, ioc_ifreq->sastr, ioc_ifreq->error);
948 
949 
950 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
951 
952 	sin = (struct sockaddr_in *)(void *)&ifr.ifr_addr;
953 	sin->sin_len = ioc_ifreq->salen;
954 	sin->sin_family = ioc_ifreq->safamily;
955 	sin->sin_addr.s_addr = inet_addr(ioc_ifreq->sastr);
956 
957 	int retval;
958 	if (ioc_ifreq->error == 0) {
959 		T_EXPECT_POSIX_SUCCESS(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifr),
960 		    "%s, %s: retval %d", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval);
961 	} else {
962 		T_EXPECT_POSIX_FAILURE(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifr), ioc_ifreq->error,
963 		    "%s, %s: retval %d errno %s", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval, strerror(errno));
964 	}
965 
966 	fflush(stdout);
967 	fflush(stderr);
968 }
969 
970 static void
test_sioc_ifr_addr_config_v6(struct ioc_ifreq * ioc_ifreq,int s,const char * ifname)971 test_sioc_ifr_addr_config_v6(struct ioc_ifreq *ioc_ifreq, int s, const char *ifname)
972 {
973 	struct in6_aliasreq     ifra = {{ 0 }, { 0 }, { 0 }, { 0 }, 0, { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME }};
974 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)(void *)&ifra.ifra_addr;
975 	struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)(void *)&ifra.ifra_prefixmask;
976 	T_LOG("");
977 	T_LOG("TEST CASE: %s ioctl(%s, sa_len %u, sa_family %u, %s) -> %d", __func__,
978 	    ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->salen, ioc_ifreq->safamily, ioc_ifreq->sastr, ioc_ifreq->error);
979 
980 	strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
981 
982 	sin6->sin6_len = ioc_ifreq->salen;
983 	sin6->sin6_family = ioc_ifreq->safamily;
984 	T_ASSERT_EQ(inet_pton(AF_INET6, ioc_ifreq->sastr, &sin6->sin6_addr), 1, NULL);
985 	sin6->sin6_scope_id = if_nametoindex(ifname);
986 
987 	mask6->sin6_len = ioc_ifreq->salen;
988 	mask6->sin6_family = ioc_ifreq->safamily;
989 	T_ASSERT_EQ(inet_pton(AF_INET6, "ffff:ffff:ffff:ffff::", &mask6->sin6_addr), 1, NULL);
990 
991 	ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
992 	ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
993 
994 	int retval;
995 	if (ioc_ifreq->error == 0) {
996 		T_EXPECT_POSIX_SUCCESS(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifra),
997 		    "%s, %s: retval %d", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval);
998 	} else {
999 		T_EXPECT_POSIX_FAILURE(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifra), ioc_ifreq->error,
1000 		    "%s, %s: retval %d errno %s", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval, strerror(errno));
1001 	}
1002 
1003 	fflush(stdout);
1004 	fflush(stderr);
1005 }
1006 
1007 
1008 T_DECL(sioc_ifr_addr_config, "test failure cases for interface address configuration ioctls",
1009     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
1010 {
1011 	int s = -1;
1012 	int s6 = -1;
1013 	char ifname[IFNAMSIZ];
1014 
1015 	T_LOG("%s", __func__);
1016 
1017 	T_QUIET; T_EXPECT_POSIX_SUCCESS(s = socket(AF_INET, SOCK_DGRAM, 0), "socket");
1018 	T_QUIET; T_EXPECT_POSIX_SUCCESS(s6 = socket(AF_INET6, SOCK_DGRAM, 0), "socket");
1019 
1020 	strlcpy(ifname, IF_NAME, sizeof(ifname));
1021 
1022 	int error = 0;
1023 	if ((error = ifnet_create(s, ifname, sizeof(ifname))) != 0) {
1024 		if (error == EINVAL) {
1025 			T_SKIP("The system does not support the %s cloning interface", IF_NAME);
1026 		}
1027 		T_SKIP("This test failed creating a %s cloning interface", IF_NAME);
1028 	}
1029 	T_LOG("created clone interface '%s'", ifname);
1030 
1031 	struct ioc_ifreq *ioc_ifreq;
1032 	for (ioc_ifreq = ioc_list_config; ioc_ifreq->error != -1; ioc_ifreq++) {
1033 		if (ioc_ifreq->safamily == AF_INET) {
1034 			test_sioc_ifr_addr_config_v4(ioc_ifreq, s, ifname);
1035 		} else if (ioc_ifreq->safamily == AF_INET6) {
1036 			test_sioc_ifr_addr_config_v6(ioc_ifreq, s6, ifname);
1037 		}
1038 	}
1039 	print_rt_iflist2(__func__);
1040 	(void)ifnet_destroy(s, ifname, true);
1041 
1042 	close(s);
1043 	close(s6);
1044 }
1045 
1046 /**
1047 ** Test SIOCPROTOATTACH, SIOCPROTOATTACH_IN6
1048 **/
1049 static int S_socket = -1;
1050 
1051 static int
get_inet_dgram_socket(void)1052 get_inet_dgram_socket(void)
1053 {
1054 	if (S_socket >= 0) {
1055 		return S_socket;
1056 	}
1057 	S_socket = socket(AF_INET, SOCK_DGRAM, 0);
1058 	T_QUIET;
1059 	T_ASSERT_POSIX_SUCCESS(S_socket, "socket(AF_INET, SOCK_DGRAM, 0)");
1060 	return S_socket;
1061 }
1062 
1063 static void
close_inet_dgram_socket(void)1064 close_inet_dgram_socket(void)
1065 {
1066 	if (S_socket >= 0) {
1067 		close(S_socket);
1068 		S_socket = -1;
1069 	}
1070 }
1071 
1072 static int S_socket_6 = -1;
1073 
1074 static int
get_inet6_dgram_socket(void)1075 get_inet6_dgram_socket(void)
1076 {
1077 	if (S_socket_6 >= 0) {
1078 		return S_socket_6;
1079 	}
1080 	S_socket_6 = socket(AF_INET6, SOCK_DGRAM, 0);
1081 	T_QUIET;
1082 	T_ASSERT_POSIX_SUCCESS(S_socket_6, "socket(AF_INET6, SOCK_DGRAM, 0)");
1083 	return S_socket_6;
1084 }
1085 
1086 static void
close_inet6_dgram_socket(void)1087 close_inet6_dgram_socket(void)
1088 {
1089 	if (S_socket_6 >= 0) {
1090 		close(S_socket_6);
1091 		S_socket_6 = -1;
1092 	}
1093 }
1094 
1095 static char ifname[IFNAMSIZ];
1096 
1097 static void
test_proto_attach_cleanup(void)1098 test_proto_attach_cleanup(void)
1099 {
1100 	if (ifname[0] != '\0') {
1101 		int     s;
1102 
1103 		s = get_inet_dgram_socket();
1104 		(void)ifnet_destroy(s, ifname, false);
1105 		T_LOG("Destroyed '%s'", ifname);
1106 		ifname[0] = '\0';
1107 	}
1108 }
1109 
1110 static void
test_proto_attach_atend(void)1111 test_proto_attach_atend(void)
1112 {
1113 	test_proto_attach_cleanup();
1114 	close_inet_dgram_socket();
1115 	close_inet6_dgram_socket();
1116 }
1117 
1118 static void
test_proto_attach(void)1119 test_proto_attach(void)
1120 {
1121 	int             error;
1122 	struct ifreq    ifr;
1123 	int             s;
1124 	int             s6;
1125 
1126 	T_ATEND(test_proto_attach_atend);
1127 	s = get_inet_dgram_socket();
1128 	strlcpy(ifname, "feth", sizeof(ifname));
1129 	error = ifnet_create(s, ifname, sizeof(ifname));
1130 	if (error != 0) {
1131 		if (error == EINVAL) {
1132 			T_SKIP("%s cloning interface not supported", ifname);
1133 		}
1134 		T_SKIP("%s cloning interface failed", ifname);
1135 	}
1136 	T_LOG("Created '%s'", ifname);
1137 
1138 	/* first proto attach should succeed */
1139 	bzero(&ifr, sizeof(ifr));
1140 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1141 	error = ioctl(s, SIOCPROTOATTACH, &ifr);
1142 	T_ASSERT_POSIX_SUCCESS(error, "SIOCPROTOATTACH %s succeeded",
1143 	    ifr.ifr_name);
1144 
1145 	/* second proto attach should fail with EEXIST */
1146 	error = ioctl(s, SIOCPROTOATTACH, &ifr);
1147 	T_ASSERT_POSIX_FAILURE(error, EEXIST,
1148 	    "SIOCPROTOATTACH %s failed as expected",
1149 	    ifr.ifr_name);
1150 
1151 	/* first proto attach should succeed */
1152 	s6 = get_inet6_dgram_socket();
1153 	bzero(&ifr, sizeof(ifr));
1154 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1155 	error = ioctl(s6, SIOCPROTOATTACH_IN6, &ifr);
1156 	T_ASSERT_POSIX_SUCCESS(error,
1157 	    "SIOCPROTOATTACH_IN6 %s succeeded",
1158 	    ifr.ifr_name);
1159 
1160 	/* second proto attach should fail with EEXIST */
1161 	error = ioctl(s6, SIOCPROTOATTACH_IN6, &ifr);
1162 	T_ASSERT_POSIX_FAILURE(error, EEXIST,
1163 	    "SIOCPROTOATTACH_IN6 %s failed as expected",
1164 	    ifr.ifr_name);
1165 	test_proto_attach_cleanup();
1166 }
1167 
1168 T_DECL(sioc_proto_attach, "test protocol attachment",
1169     T_META_ASROOT(true), T_META_TAG_VM_PREFERRED)
1170 {
1171 	test_proto_attach();
1172 }
1173 
1174 /*
1175  * The following is only meant to be run from the command line
1176  * when one adds a new socket interface ioctl
1177  */
1178 T_DECL(sioc_print_all, "print all socket interface ioctls", T_META_ENABLED(false), T_META_TAG_VM_PREFERRED)
1179 {
1180 #define X(a) T_LOG("%-32s 0x%08lx GROUP %3lu BASECMD %3ld LEN %4lu\n", \
1181     #a, a, (a & 0x00000ff00) >> 8, a & 0x000000ff, IOCPARM_LEN(a));
1182 	SIOC_LIST
1183 #undef X
1184 }
1185