NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/60669: netipsec key_sp2msg buffer overrun



Patch attached to fix and add tests for setsockopt/getsockopt2
IPV6_IPSEC_POLICY buffer overrun.  Review welcome!

Questions: Does it make sense to have mismatched src/dst address
families in a single IPsec policy?  Does it make sense to have a
number of addresses in a policy other than zero or two?  If not, we
can block those various cases earlier and update the tests.

Should maybe do similarly for IPv4 but there's currently no getsockopt
or getsockopt2 path for it anyway -- it's under #if 0:

   1392 #if 0	/* defined(IPSEC) */
   1393 		case IP_IPSEC_POLICY:
   1394 		{
   1395 			struct mbuf *m = NULL;
   1396 
   1397 			/* XXX this will return EINVAL as sopt is empty */
   1398 			error = ipsec_get_policy(inp, sopt->sopt_data,
   1399 			    sopt->sopt_size, &m);
   1400 			if (error == 0)
   1401 				error = sockopt_setmbuf(sopt, m);
   1402 			break;
   1403 		}
   1404 #endif /*IPSEC*/

https://nxr.NetBSD.org/xref/src/sys/netinet/ip_output.c?r=1.330#1392

The IPv6 version has the same comment but it is wrong because
getsockopt2 does allow the caller to pass input through sopt:

   1934 #if defined(IPSEC)
   1935 		case IPV6_IPSEC_POLICY:
   1936 			if (ipsec_used) {
   1937 				struct mbuf *m = NULL;
   1938 
   1939 				/*
   1940 				 * XXX: this will return EINVAL as sopt is
   1941 				 * empty
   1942 				 */
   1943 				error = ipsec_get_policy(inp, sopt->sopt_data,
   1944 				    sopt->sopt_size, &m);
   1945 				if (!error)
   1946 					error = sockopt_setmbuf(sopt, m);
   1947 			} else
   1948 				error = ENOPROTOOPT;
   1949 			break;
   1950 #endif /* IPSEC */

https://nxr.NetBSD.org/xref/src/sys/netinet6/ip6_output.c?r=1.235#1934
# HG changeset patch
# User Taylor R Campbell <riastradh%NetBSD.org@localhost>
# Date 1788120878 0
#      Sun Aug 30 20:14:38 2026 +0000
# Branch trunk
# Node ID f1ab0b6f9d43f3e6660ad717571d357c6c195b6e
# Parent  4fbd288ac1da9e7d9592ddecf04f7513e244152f
# EXP-Topic riastradh-pr60669-sp2msgoverrun
ipsec: Fix sizing and alignment in IPsec policy import and export.

Note: I'm not sure whether it makes sense to have mismatched src and
dst address families -- I doubt it, since userland libipsec rejects
it in ipsec_set_policy(3).  I'm also not sure whether it makes sense
to have numbers of addresses other than 0 or 2.  But those can be
addressed in a separate commit.

PR kern/60669: netipsec key_sp2msg buffer overrun

diff -r 4fbd288ac1da -r f1ab0b6f9d43 sys/netipsec/key.c
--- a/sys/netipsec/key.c	Mon Aug 10 13:36:10 2026 +0000
+++ b/sys/netipsec/key.c	Sun Aug 30 20:14:38 2026 +0000
@@ -1873,7 +1873,7 @@ static struct secpolicy *
 	struct ipsecrequest **p_isr = &newsp->req;
 
 	/* validity check */
-	if (PFKEY_EXTLEN(xpl0) < sizeof(*xpl0)) {
+	if (PFKEY_EXTLEN(xpl0) < sizeof(*xpl0) + sizeof(*xisr)) {
 		IPSECLOG(LOG_DEBUG, "Invalid msg length.\n");
 		*error = EINVAL;
 		goto free_exit;
@@ -1882,9 +1882,11 @@ static struct secpolicy *
 	tlen = PFKEY_EXTLEN(xpl0) - sizeof(*xpl0);
 	xisr = (const struct sadb_x_ipsecrequest *)(xpl0 + 1);
 
-	while (tlen > 0) {
+	while (tlen > sizeof(*xisr)) {
 		/* length check */
-		if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) {
+		if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr) ||
+		    xisr->sadb_x_ipsecrequest_len > tlen ||
+		    xisr->sadb_x_ipsecrequest_len % 8 != 0) {
 			IPSECLOG(LOG_DEBUG, "invalid ipsecrequest length.\n");
 			*error = EINVAL;
 			goto free_exit;
@@ -1991,12 +1993,21 @@ static struct secpolicy *
 		 * This behavior is used by NAT-T enabled ipsecif(4).
 		 */
 		if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
+			size_t resid = xisr->sadb_x_ipsecrequest_len;
 			const struct sockaddr *paddr;
 
+			if (sizeof(*paddr) > resid) {
+				IPSECLOG(LOG_DEBUG, "invalid request "
+				    "address length.\n");
+				*error = EINVAL;
+				goto free_exit;
+			}
 			paddr = (const struct sockaddr *)(xisr + 1);
 
 			/* validity check */
-			if (paddr->sa_len > sizeof((*p_isr)->saidx.src)) {
+			if (paddr->sa_len < sizeof(*paddr) ||
+			    paddr->sa_len > resid ||
+			    paddr->sa_len > sizeof((*p_isr)->saidx.src)) {
 				IPSECLOG(LOG_DEBUG, "invalid request "
 				    "address length.\n");
 				*error = EINVAL;
@@ -2004,11 +2015,20 @@ static struct secpolicy *
 			}
 			memcpy(&(*p_isr)->saidx.src, paddr, paddr->sa_len);
 
+			resid -= paddr->sa_len;
+			if (sizeof(*paddr) > resid) {
+				IPSECLOG(LOG_DEBUG, "invalid request "
+				    "address length 2, %zu > %zu.\n", sizeof(*paddr), resid);
+				*error = EINVAL;
+				goto free_exit;
+			}
 			paddr = (const struct sockaddr *)((const char *)paddr
 			    + paddr->sa_len);
 
 			/* validity check */
-			if (paddr->sa_len > sizeof((*p_isr)->saidx.dst)) {
+			if (paddr->sa_len < sizeof(*paddr) ||
+			    paddr->sa_len > resid ||
+			    paddr->sa_len > sizeof((*p_isr)->saidx.dst)) {
 				IPSECLOG(LOG_DEBUG, "invalid request "
 				    "address length.\n");
 				*error = EINVAL;
@@ -2024,11 +2044,7 @@ static struct secpolicy *
 		tlen -= xisr->sadb_x_ipsecrequest_len;
 
 		/* validity check */
-		if (tlen < 0) {
-			IPSECLOG(LOG_DEBUG, "becoming tlen < 0.\n");
-			*error = EINVAL;
-			goto free_exit;
-		}
+		KASSERT(tlen >= 0);
 
 		xisr = (const struct sadb_x_ipsecrequest *)((const char *)xisr +
 		    xisr->sadb_x_ipsecrequest_len);
@@ -2071,7 +2087,7 @@ key_sp2msg(const struct secpolicy *sp, i
 {
 	struct sadb_x_policy *xpl;
 	int tlen;
-	char *p;
+	char *p0, *p;
 	struct mbuf *m;
 
 	KASSERT(sp != NULL);
@@ -2086,6 +2102,9 @@ key_sp2msg(const struct secpolicy *sp, i
 
 	m->m_len = tlen;
 	m->m_next = NULL;
+	p0 = m->m_data;
+	KASSERT(sizeof(struct sadb_x_policy) <= tlen);
+	KASSERT((uintptr_t)p0 % _Alignof(struct sadb_x_policy) == 0);
 	xpl = mtod(m, struct sadb_x_policy *);
 	memset(xpl, 0, tlen);
 
@@ -2096,7 +2115,9 @@ key_sp2msg(const struct secpolicy *sp, i
 	xpl->sadb_x_policy_id = sp->id;
 	if (sp->origin == IPSEC_SPORIGIN_KERNEL)
 		xpl->sadb_x_policy_flags |= IPSEC_POLICY_FLAG_ORIGIN_KERNEL;
+	CTASSERT(sizeof(*xpl) % 8 == 0);
 	p = (char *)xpl + sizeof(*xpl);
+	KASSERT((p - p0) % 8 == 0);
 
 	/* if is the policy for ipsec ? */
 	if (sp->policy == IPSEC_POLICY_IPSEC) {
@@ -2104,24 +2125,40 @@ key_sp2msg(const struct secpolicy *sp, i
 		struct ipsecrequest *isr;
 
 		for (isr = sp->req; isr != NULL; isr = isr->next) {
-
+			const unsigned len = sizeof(*xisr)
+			    + isr->saidx.src.sa.sa_len
+			    + isr->saidx.dst.sa.sa_len;
+			const unsigned pad = PFKEY_ALIGN8(len) - len;
+
+			KASSERT((p - p0) % 8 == 0);
+			KASSERT(PFKEY_ALIGN8(len) <= tlen - (p - p0));
+
+			KASSERT(sizeof(*xisr) <= tlen - (p - p0));
 			xisr = (struct sadb_x_ipsecrequest *)p;
 
 			xisr->sadb_x_ipsecrequest_proto = isr->saidx.proto;
 			xisr->sadb_x_ipsecrequest_mode = isr->saidx.mode;
 			xisr->sadb_x_ipsecrequest_level = isr->level;
 			xisr->sadb_x_ipsecrequest_reqid = isr->saidx.reqid;
-
 			p += sizeof(*xisr);
+
+			KASSERT(isr->saidx.src.sa.sa_len <= tlen - (p - p0));
 			memcpy(p, &isr->saidx.src, isr->saidx.src.sa.sa_len);
 			p += isr->saidx.src.sa.sa_len;
+
+			KASSERT(isr->saidx.dst.sa.sa_len <= tlen - (p - p0));
 			memcpy(p, &isr->saidx.dst, isr->saidx.dst.sa.sa_len);
-			p += isr->saidx.src.sa.sa_len;
-
-			xisr->sadb_x_ipsecrequest_len =
-			    PFKEY_ALIGN8(sizeof(*xisr)
-			    + isr->saidx.src.sa.sa_len
-			    + isr->saidx.dst.sa.sa_len);
+			p += isr->saidx.dst.sa.sa_len;
+
+			KASSERT(pad <= tlen - (p - p0));
+			memset(p, 0, pad);
+			p += pad;
+
+			KASSERT(p == (char *)xisr + PFKEY_ALIGN8(len));
+			KASSERT((p - p0) % 8 == 0);
+			xisr->sadb_x_ipsecrequest_len = PFKEY_ALIGN8(len);
+			KASSERT(p == (char *)xisr +
+			    xisr->sadb_x_ipsecrequest_len);
 		}
 	}
 
# HG changeset patch
# User Taylor R Campbell <riastradh%NetBSD.org@localhost>
# Date 1788121188 0
#      Sun Aug 30 20:19:48 2026 +0000
# Branch trunk
# Node ID e10c5a00f1259f9573a35186ed44c4693099f97f
# Parent  f1ab0b6f9d43f3e6660ad717571d357c6c195b6e
# EXP-Topic riastradh-pr60669-sp2msgoverrun
ipsec: Test edge cases of setting and getting IPsec policies.

PR kern/60669: netipsec key_sp2msg buffer overrun

diff -r f1ab0b6f9d43 -r e10c5a00f125 distrib/sets/lists/debug/mi
--- a/distrib/sets/lists/debug/mi	Sun Aug 30 20:14:38 2026 +0000
+++ b/distrib/sets/lists/debug/mi	Sun Aug 30 20:19:48 2026 +0000
@@ -2528,6 +2528,7 @@
 ./usr/libdata/debug/usr/tests/net/inpcb/broadcast_bind.debug	tests-net-debug		debug,atf,rump,compattestfile
 ./usr/libdata/debug/usr/tests/net/inpcb/inpcb_bind.debug	tests-net-debug		debug,atf,rump,compattestfile
 ./usr/libdata/debug/usr/tests/net/ipsec/natt_terminator.debug	tests-net-debug		debug,atf,rump
+./usr/libdata/debug/usr/tests/net/ipsec/t_ipsec_policy.debug	tests-net-debug		debug,atf,rump
 ./usr/libdata/debug/usr/tests/net/mcast/mcast.debug		tests-net-debug		debug,atf,rump
 ./usr/libdata/debug/usr/tests/net/mcast/t_mcast.debug		tests-obsolete		debug,atf,rump,obsolete
 ./usr/libdata/debug/usr/tests/net/net/t_bind.debug		tests-net-debug		debug,atf,compattestfile
diff -r f1ab0b6f9d43 -r e10c5a00f125 distrib/sets/lists/tests/mi
--- a/distrib/sets/lists/tests/mi	Sun Aug 30 20:14:38 2026 +0000
+++ b/distrib/sets/lists/tests/mi	Sun Aug 30 20:19:48 2026 +0000
@@ -4607,6 +4607,7 @@
 ./usr/tests/net/ipsec/t_ipsec_l2tp			tests-net-tests		atf,rump
 ./usr/tests/net/ipsec/t_ipsec_misc			tests-net-tests		atf,rump
 ./usr/tests/net/ipsec/t_ipsec_natt			tests-net-tests		atf,rump
+./usr/tests/net/ipsec/t_ipsec_policy			tests-net-tests		atf,rump
 ./usr/tests/net/ipsec/t_ipsec_sockopt			tests-net-tests		atf,rump
 ./usr/tests/net/ipsec/t_ipsec_spflags			tests-net-tests		atf,rump
 ./usr/tests/net/ipsec/t_ipsec_sysctl			tests-net-tests		atf,rump
diff -r f1ab0b6f9d43 -r e10c5a00f125 tests/net/ipsec/Makefile
--- a/tests/net/ipsec/Makefile	Sun Aug 30 20:14:38 2026 +0000
+++ b/tests/net/ipsec/Makefile	Sun Aug 30 20:19:48 2026 +0000
@@ -13,6 +13,8 @@ TESTS_SH_SRC_t_${name}=	../net_common.sh
     t_${name}.sh
 .endfor
 
+TESTS_C+=		t_ipsec_policy
+
 PROGS=			natt_terminator
 MAN.natt_terminator=	# empty
 BINDIR.natt_terminator=	${TESTSDIR}
diff -r f1ab0b6f9d43 -r e10c5a00f125 tests/net/ipsec/t_ipsec_policy.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/net/ipsec/t_ipsec_policy.c	Sun Aug 30 20:19:48 2026 +0000
@@ -0,0 +1,354 @@
+/*	$NetBSD$	*/
+
+/*
+ * Copyright (c) 2026 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include <arpa/inet.h>
+#include <net/pfkeyv2.h>
+#include <netinet/in.h>
+#include <netipsec/ipsec.h>
+
+#include <atf-c.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "h_macros.h"
+
+static void
+hexdump(const char *title, const void *buf, size_t len)
+{
+	const uint8_t *p = buf;
+	size_t i;
+
+	printf("# %s (%zu bytes)\n", title, len);
+	for (i = 0; i < len; i++) {
+		if ((i % 8) == 0)
+			printf(" ");
+		printf(" %02hhx", p[i]);
+		if ((i % 16) == 15)
+			printf("\n");
+	}
+	if (i % 16)
+		printf("\n");
+}
+
+static void *
+append(void **bufp, size_t *buflenp, size_t addlen)
+{
+	void *p;
+
+	if (addlen == 0)
+		return NULL;
+
+	ATF_REQUIRE(addlen < SIZE_MAX - *buflenp);
+	RZ(reallocarr(bufp, *buflenp + addlen, 1));
+	p = (char *)*bufp + *buflenp;
+	memset(p, 0, addlen);
+	*buflenp += addlen;
+	return p;
+}
+
+static void
+test_ipsec_policy_roundtrip(int exp_error, uint8_t dir,
+    const struct sockaddr *src, const struct sockaddr *dst)
+{
+	enum { guardlen =  8 };
+	void *buf = NULL;
+	size_t len = 0;
+	struct sadb_x_policy *xpl, *xpl1;
+	size_t xpl_start, xpl1_start;
+	size_t reqlen;
+	void *copybuf = NULL;
+	size_t copylen = 0;
+	uint8_t guardbyte[2] = {0x5a, 0x3c};
+	size_t guard_start[2];
+	socklen_t optlen;
+	unsigned i;
+	int s;
+
+	xpl_start = len;
+	xpl = append(&buf, &len, sizeof(*xpl));
+	xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+	xpl->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
+	xpl->sadb_x_policy_dir = dir;
+
+	for (i = 0; i < 2; i++) {
+		const size_t xisr_start = len;
+		struct sadb_x_ipsecrequest *xisr;
+
+		xisr = append(&buf, &len, sizeof(*xisr));
+		xisr->sadb_x_ipsecrequest_proto = IPPROTO_ESP;
+		xisr->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL;
+		xisr->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE;
+		xisr->sadb_x_ipsecrequest_reqid = 0;
+
+		memcpy(append(&buf, &len, src->sa_len), src, src->sa_len);
+		memcpy(append(&buf, &len, dst->sa_len), dst, dst->sa_len);
+
+		/* pad */
+		const size_t npad = PFKEY_ALIGN8(len - xisr_start) -
+		    (len - xisr_start);
+		(void)append(&buf, &len, npad);
+
+		ATF_REQUIRE(PFKEY_ALIGN8(len - xisr_start) == len - xisr_start);
+		xisr = (void *)((char *)buf + xisr_start);
+		xisr->sadb_x_ipsecrequest_len = len - xisr_start;
+	}
+
+	ATF_REQUIRE(PFKEY_ALIGN8(len - xpl_start) == len - xpl_start);
+	xpl = (void *)((char *)buf + xpl_start);
+	xpl->sadb_x_policy_len = PFKEY_UNIT64(len - xpl_start);
+
+	reqlen = len - xpl_start;
+
+	RL(s = socket(AF_INET6, SOCK_DGRAM, 0));
+	if (exp_error) {
+		ATF_CHECK_ERRNO(exp_error,
+		    setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, xpl, reqlen)
+		    == -1);
+		goto out;
+	}
+	if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, xpl, reqlen)
+	    == -1) {
+		int error = errno;
+
+		atf_tc_fail_nonfatal("setsockopt(IPV6_IPSEC_POLICY): %d (%s)",
+		    error, strerror(errno));
+		goto out;
+	}
+
+	guard_start[0] = copylen;
+	memset(append(&copybuf, &copylen, guardlen), guardbyte[0], guardlen);
+
+	xpl1_start = copylen;
+	(void *)append(&copybuf, &copylen, reqlen);
+
+	guard_start[1] = copylen;
+	memset(append(&copybuf, &copylen, guardlen), guardbyte[1], guardlen);
+
+	xpl = (void *)((char *)buf + xpl_start);
+	xpl1 = (void *)((char *)copybuf + xpl1_start);
+	memcpy(xpl1, xpl, reqlen);
+
+	optlen = reqlen;
+	ATF_CHECK_ERRNO(EINVAL,
+	    getsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, xpl1, &optlen));
+
+	optlen = reqlen;
+	if (getsockopt2(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, xpl1, &optlen)
+	    == -1) {
+		int error = errno;
+
+		atf_tc_fail_nonfatal("getsockopt2(IPV6_IPSEC_POLICY): %d (%s)",
+		    error, strerror(errno));
+		goto out;
+	}
+	ATF_CHECK_EQ_MSG(reqlen, optlen, "reqlen=%zu optlen=%zu",
+	    (size_t)reqlen, (size_t)optlen);
+
+	if (reqlen != optlen || memcmp(xpl, xpl1, len) != 0) {
+		hexdump("before", xpl, reqlen);
+		hexdump("after", xpl1, optlen);
+		fflush(stdout);
+		atf_tc_fail_nonfatal("mismatch");
+	}
+
+	for (i = 0; i < __arraycount(guard_start); i++) {
+		const char *guard = (char *)copybuf + guard_start[i];
+		size_t j;
+
+		for (j = 0; j < guardlen; j++) {
+			if (guard[j] != guardbyte[i]) {
+				char title[8];
+
+				snprintf(title, sizeof(title), "guard %u", i);
+				hexdump(title, guard, guardlen);
+				fflush(stdout);
+				atf_tc_fail_nonfatal("guard %u overwritten",
+				    i);
+				break;
+			}
+		}
+	}
+
+out:	RL(close(s));
+}
+
+ATF_TC(pr60669);
+ATF_TC_HEAD(pr60669, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "Test IPV6_IPSEC_POLICY round-trip with"
+	    " v4 src and v4 dst");
+}
+ATF_TC_BODY(pr60669, tc)
+{
+	union {
+		struct sockaddr sa;
+		struct sockaddr_in sin;
+	} v4[2] = {
+		[0] = {
+			.sin = {
+				.sin_len = sizeof(v4[0].sin),
+				.sin_family = AF_INET,
+				.sin_port = 0,
+			}
+		},
+		[1] = {
+			.sin = {
+				.sin_len = sizeof(v4[1].sin),
+				.sin_family = AF_INET,
+				.sin_port = 0,
+			}
+		},
+	};
+	union {
+		struct sockaddr sa;
+		struct sockaddr_in6 sin6;
+	} v6[2] = {
+		[0] = {
+			.sin6 = {
+				.sin6_len = sizeof(v6[0].sin6),
+				.sin6_family = AF_INET6,
+				.sin6_port = 0,
+			}
+		},
+		[1] = {
+			.sin6 = {
+				.sin6_len = sizeof(v6[1].sin6),
+				.sin6_family = AF_INET6,
+				.sin6_port = 0,
+			}
+		},
+	};
+	union {
+		struct sockaddr sa;
+		struct sockaddr_un sun;
+	} un[2] = {
+		[0] = {
+			.sun = {
+				.sun_len = -1,
+				.sun_family = AF_LOCAL,
+				.sun_path = "/socket0",
+			}
+		},
+		[1] = {
+			.sun = {
+				.sun_len = -1,
+				.sun_family = AF_LOCAL,
+				.sun_path = "/socket1",
+			}
+		},
+	};
+	struct sockaddr sa[2] = {
+		[0] = { .sa_len = sizeof(sa[0]), .sa_family = AF_UNSPEC },
+		[1] = { .sa_len = sizeof(sa[1]), .sa_family = AF_UNSPEC },
+	};
+	struct sockaddr sa0[2] = {
+		[0] = { .sa_len = 0, .sa_family = AF_UNSPEC },
+		[1] = { .sa_len = 0, .sa_family = AF_UNSPEC },
+	};
+	const struct {
+		struct sockaddr *src;
+		struct sockaddr *dst;
+		int expected_error;
+		const char *xfail;
+	} C[] = {
+		[0] = { &v4[0].sa, &v4[1].sa, 0, NULL },
+		[1] = { &v4[0].sa, &v6[1].sa, 0, NULL },
+		[2] = { &v4[0].sa, &un[1].sa, EINVAL, NULL },
+		[3] = { &v4[0].sa, &sa[1], 0, NULL },
+		[4] = { &v4[0].sa, &sa0[1], EINVAL, NULL },
+
+		[5] = { &v6[0].sa, &v4[1].sa, 0, NULL },
+		[6] = { &v6[0].sa, &v6[1].sa, 0, NULL },
+		[7] = { &v6[0].sa, &un[1].sa, EINVAL, NULL },
+		[8] = { &v6[0].sa, &sa[1], 0, NULL },
+		[9] = { &v6[0].sa, &sa0[1], EINVAL, NULL },
+
+		[10] = { &un[0].sa, &v4[1].sa, EINVAL, NULL },
+		[11] = { &un[0].sa, &v6[1].sa, EINVAL, NULL },
+		[12] = { &un[0].sa, &un[1].sa, EINVAL, NULL },
+		[13] = { &un[0].sa, &sa[1], EINVAL, NULL },
+		[14] = { &un[0].sa, &sa0[1], EINVAL, NULL },
+
+		[15] = { &sa[0], &v4[1].sa, 0, NULL },
+		[16] = { &sa[0], &v6[1].sa, 0, NULL },
+		[17] = { &sa[0], &un[1].sa, EINVAL, NULL },
+		[18] = { &sa[0], &sa[1], 0, NULL },
+		[19] = { &sa[0], &sa0[1], EINVAL, NULL },
+
+		/*
+		 * sa0 as the src one doesn't even make sense to test,
+		 * because sa_len won't even advance past it, so it
+		 * will be the same as testing a nonempty src and sa0
+		 * dst above.
+		 */
+	};
+	unsigned i;
+
+	RL(inet_pton(AF_INET, "192.0.2.42", &v4[0].sin.sin_addr));
+	RL(inet_pton(AF_INET, "192.51.100.54", &v4[1].sin.sin_addr));
+
+	RL(inet_pton(AF_INET6, "2001:db8:1::1", &v6[0].sin6.sin6_addr));
+	RL(inet_pton(AF_INET6, "2001:db8:2::1", &v6[1].sin6.sin6_addr));
+
+	un[0].sun.sun_len = SUN_LEN(&un[0].sun);
+	un[1].sun.sun_len = SUN_LEN(&un[1].sun);
+
+	for (i = 0; i < __arraycount(C); i++) {
+		const char *const dirname[2] = { "inbound", "outbound" };
+		const unsigned dir[2] =
+		    { IPSEC_DIR_INBOUND, IPSEC_DIR_OUTBOUND };
+		unsigned j;
+
+		for (j = 0; j < 2; j++) {
+			printf("# case %u %s\n", i, dirname[j]);
+			fflush(stdout);
+			if (C[i].xfail)
+				atf_tc_expect_fail("%s", C[i].xfail);
+			test_ipsec_policy_roundtrip(C[i].expected_error,
+			    dir[j], C[i].src, C[i].dst);
+			if (C[i].xfail)
+				atf_tc_expect_pass();
+		}
+	}
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+	ATF_TP_ADD_TC(tp, pr60669);
+	return atf_no_error();
+}
+


Home | Main Index | Thread Index | Old Index