changeset 3192:e4e2ffd4e00f

6478675 inconsistent ESP padding verification in OpenSolaris Contributed by Jean-Paul Degabriele <jeanpaul.degabriele@gmail.com>. 6481387 Freed queue_t gets passed to ipsec_log_policy_failure() during OPL ttcp runs... 6494630 qs21 may be validating cert chains incorrectly. 6495455 assertion failure when using IPsec global policy with IPv6 tunnels 6496323 AH-only on tunnels doesn't work. 6497625 More debugging and output cleanliness in in.iked's cert-chain processing.
author danmcd
date Wed, 29 Nov 2006 16:09:14 -0800
parents 6941d6cb4c23
children 18a2947957c4
files usr/src/uts/common/inet/ip/ipsecah.c usr/src/uts/common/inet/ip/ipsecesp.c usr/src/uts/common/inet/ip/spd.c usr/src/uts/common/inet/ipsec_impl.h usr/src/uts/common/inet/tcp/tcp.c
diffstat 5 files changed, 163 insertions(+), 151 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/inet/ip/ipsecah.c	Tue Nov 28 16:45:29 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ipsecah.c	Wed Nov 29 16:09:14 2006 -0800
@@ -35,6 +35,7 @@
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
 #include <sys/kmem.h>
+#include <sys/sysmacros.h>
 #include <sys/cmn_err.h>
 #include <sys/vtrace.h>
 #include <sys/debug.h>
@@ -3726,14 +3727,14 @@
 	ipha_t *ipha;
 	uint_t ah_offset = 0;
 	mblk_t *mp;
-	int align_len;
+	int align_len, newpos;
 	ah_t *ah;
-	ipha_t *nipha;
 	uint32_t length;
+	uint32_t *dest32;
+	uint8_t *dest;
 	ipsec_in_t *ii;
 	boolean_t isv4;
 	ip6_t *ip6h;
-	ip6_t *nip6h;
 	uint_t icv_len;
 	ipsa_t *assoc;
 	kstat_named_t *counter;
@@ -3774,6 +3775,7 @@
 	}
 
 	ah = (ah_t *)(mp->b_rptr + ah_offset);
+	newpos = sizeof (ah_t) + align_len;
 
 	/*
 	 * We get here only when authentication passed.
@@ -3812,22 +3814,18 @@
 
 	/*
 	 * We need to remove the AH header from the original
-	 * datagram. Easy way to do this is to use phdr_mp
-	 * to hold the IP header and the orginal mp to hold
-	 * the rest of it. So, we copy the IP header on to
-	 * phdr_mp, and set the b_rptr in mp past AH header.
+	 * datagram. Best way to do this is to move the pre-AH headers
+	 * forward in the (relatively simple) IPv4 case.  In IPv6, it's
+	 * a bit more complicated because of IPv6's next-header chaining,
+	 * but it's doable.
 	 */
 	if (isv4) {
-		bcopy(mp->b_rptr, phdr_mp->b_rptr, ah_offset);
-		phdr_mp->b_wptr = phdr_mp->b_rptr + ah_offset;
-		nipha = (ipha_t *)phdr_mp->b_rptr;
 		/*
 		 * Assign the right protocol, adjust the length as we
 		 * are removing the AH header and adjust the checksum to
 		 * account for the protocol and length.
 		 */
-		nipha->ipha_protocol = ah->ah_nexthdr;
-		length = ntohs(nipha->ipha_length);
+		length = ntohs(ipha->ipha_length);
 		if (!ah_age_bytes(assoc, length, B_TRUE)) {
 			/* The ipsa has hit hard expiration, LOG and AUDIT. */
 			ipsec_assocfailure(info.mi_idnum, 0, 0,
@@ -3839,16 +3837,12 @@
 			counter = &ipdrops_ah_bytes_expire;
 			goto ah_in_discard;
 		}
-		length -= (sizeof (ah_t) + align_len);
-
-		nipha->ipha_length = htons((uint16_t)length);
-		nipha->ipha_hdr_checksum = 0;
-		nipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(nipha);
-		/*
-		 * Skip IP,AH and the authentication data in the
-		 * original datagram.
-		 */
-		mp->b_rptr += (ah_offset + sizeof (ah_t) + align_len);
+		ipha->ipha_protocol = ah->ah_nexthdr;
+		length -= newpos;
+
+		ipha->ipha_length = htons((uint16_t)length);
+		ipha->ipha_hdr_checksum = 0;
+		ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha);
 	} else {
 		uchar_t *whereptr;
 		int hdrlen;
@@ -3857,13 +3851,11 @@
 		ip6_dest_t *dsthdr;
 		ip6_rthdr0_t *rthdr;
 
-		nip6h = (ip6_t *)phdr_mp->b_rptr;
-
 		/*
 		 * Make phdr_mp hold until the AH header and make
 		 * mp hold everything past AH header.
 		 */
-		length = ntohs(nip6h->ip6_plen);
+		length = ntohs(ip6h->ip6_plen);
 		if (!ah_age_bytes(assoc, length + sizeof (ip6_t), B_TRUE)) {
 			/* The ipsa has hit hard expiration, LOG and AUDIT. */
 			ipsec_assocfailure(info.mi_idnum, 0, 0,
@@ -3875,9 +3867,6 @@
 			counter = &ipdrops_ah_bytes_expire;
 			goto ah_in_discard;
 		}
-		bcopy(ip6h, nip6h, ah_offset);
-		phdr_mp->b_wptr = phdr_mp->b_rptr + ah_offset;
-		mp->b_rptr += (ah_offset + sizeof (ah_t) + align_len);
 
 		/*
 		 * Update the next header field of the header preceding
@@ -3885,8 +3874,8 @@
 		 * IPv6 header and proceed with the extension headers
 		 * until we find what we're looking for.
 		 */
-		nexthdr = &nip6h->ip6_nxt;
-		whereptr =  (uchar_t *)nip6h;
+		nexthdr = &ip6h->ip6_nxt;
+		whereptr =  (uchar_t *)ip6h;
 		hdrlen = sizeof (ip6_t);
 
 		while (*nexthdr != IPPROTO_AH) {
@@ -3913,16 +3902,29 @@
 			}
 		}
 		*nexthdr = ah->ah_nexthdr;
-
-		length -= (sizeof (ah_t) + align_len);
-		nip6h->ip6_plen = htons((uint16_t)length);
+		length -= newpos;
+		ip6h->ip6_plen = htons((uint16_t)length);
 	}
 
+	/* Now that we've fixed the IP header, move it forward. */
+	mp->b_rptr += newpos;
+	if (IS_P2ALIGNED(mp->b_rptr, sizeof (uint32_t))) {
+		dest32 = (uint32_t *)(mp->b_rptr + ah_offset);
+		while (--dest32 >= (uint32_t *)mp->b_rptr)
+			*dest32 = *(dest32 - (newpos >> 2));
+	} else {
+		dest = mp->b_rptr + ah_offset;
+		while (--dest >= mp->b_rptr)
+			*dest = *(dest - newpos);
+	}
+	freeb(phdr_mp);
+	ipsec_in->b_cont = mp;
+
 	if (is_system_labeled()) {
 		/*
 		 * inherit the label by setting it in the new ip header
 		 */
-		mblk_setcred(phdr_mp, DB_CRED(mp));
+		mblk_setcred(mp, DB_CRED(mp));
 	}
 	return (IPSEC_STATUS_SUCCESS);
 
--- a/usr/src/uts/common/inet/ip/ipsecesp.c	Tue Nov 28 16:45:29 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ipsecesp.c	Wed Nov 29 16:09:14 2006 -0800
@@ -763,7 +763,7 @@
 
 
 /*
- * Strip ESP header and fix IP header
+ * Strip ESP header, check padding, and fix IP header.
  * Returns B_TRUE on success, B_FALSE if an error occured.
  */
 static boolean_t
@@ -776,6 +776,7 @@
 	mblk_t *scratch;
 	uint8_t nexthdr, padlen;
 	uint8_t lastpad;
+	uint8_t *lastbyte;
 
 	/*
 	 * Strip ESP data and fix IP header.
@@ -807,9 +808,9 @@
 	 * lastpad is the last byte of the padding, which can be used for
 	 * a quick check to see if the padding is correct.
 	 */
-	nexthdr = *(scratch->b_wptr - 1);
-	padlen = *(scratch->b_wptr - 2);
-	lastpad = *(scratch->b_wptr - 3);
+	lastbyte = scratch->b_wptr - 1;
+	nexthdr = *lastbyte--;
+	padlen = *lastbyte--;
 
 	if (isv4) {
 		/* Fix part of the IP header. */
@@ -822,7 +823,7 @@
 		    sizeof (esph_t) - ivlen) {
 			ESP_BUMP_STAT(bad_decrypt);
 			ipsec_rl_strlog(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
-			    "Possibly corrupt ESP packet.");
+			    "Corrupt ESP packet (padlen too big).\n");
 			esp1dbg(("padlen (%d) is greater than:\n", padlen));
 			esp1dbg(("pkt len(%d) - ip hdr - esp hdr - ivlen(%d) "
 			    "= %d.\n", ntohs(ipha->ipha_length), ivlen,
@@ -867,7 +868,7 @@
 		    ivlen) {
 			ESP_BUMP_STAT(bad_decrypt);
 			ipsec_rl_strlog(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
-			    "Possibly corrupt ESP packet.");
+			    "Corrupt ESP packet (v6 padlen too big).\n");
 			esp1dbg(("padlen (%d) is greater than:\n", padlen));
 			esp1dbg(("pkt len(%u) - ip hdr - esp hdr - ivlen(%d)"
 			    " = %u.\n", (unsigned)(ntohs(ip6h->ip6_plen)
@@ -888,41 +889,57 @@
 		    2 - sizeof (esph_t) - ivlen);
 	}
 
-	if (ipsecesp_padding_check > 0 &&
-		padlen != lastpad && padlen != 0) {
-		ipsec_rl_strlog(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
-		    "Possibly corrupt ESP packet.");
-		esp1dbg(("lastpad (%d) not equal to padlen (%d):\n",
-		    lastpad, padlen));
-		ESP_BUMP_STAT(bad_padding);
-		*counter = &ipdrops_esp_bad_padding;
-		return (B_FALSE);
-	}
-
-	if (ipsecesp_padding_check > 1) {
-		uint8_t *last = (uint8_t *)(scratch->b_wptr - 3);
-		uint8_t lastval = *last;
+	if (ipsecesp_padding_check > 0 && padlen > 0) {
+		/*
+		 * Weak padding check: compare last-byte to length, they
+		 * should be equal.
+		 */
+		lastpad = *lastbyte--;
+
+		if (padlen != lastpad) {
+			ipsec_rl_strlog(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
+			    "Corrupt ESP packet (lastpad != padlen).\n");
+			esp1dbg(("lastpad (%d) not equal to padlen (%d):\n",
+				    lastpad, padlen));
+			ESP_BUMP_STAT(bad_padding);
+			*counter = &ipdrops_esp_bad_padding;
+			return (B_FALSE);
+		}
 
 		/*
-		 * this assert may have to become an if
-		 * and a pullup if we start accepting
-		 * multi-dblk mblks. Any packet here will
-		 * have been pulled up in esp_inbound.
+		 * Strong padding check: Check all pad bytes to see that
+		 * they're ascending.  Go backwards using a descending counter
+		 * to verify.  padlen == 1 is checked by previous block, so
+		 * only bother if we've more than 1 byte of padding.
+		 * Consequently, start the check one byte before the location
+		 * of "lastpad".
 		 */
-		ASSERT(MBLKL(scratch) >= lastval + 3);
-
-		while (lastval != 0) {
-			if (lastval != *last) {
-				ipsec_rl_strlog(info.mi_idnum, 0, 0,
-				    SL_ERROR | SL_WARN,
-				    "Possibly corrupt ESP packet.");
-				esp1dbg(("padding not in correct"
-				    " format:\n"));
-				ESP_BUMP_STAT(bad_padding);
-				*counter = &ipdrops_esp_bad_padding;
-				return (B_FALSE);
+		if (ipsecesp_padding_check > 1) {
+			/*
+			 * This assert may have to become an if and a pullup
+			 * if we start accepting multi-dblk mblks. For now,
+			 * though, any packet here will have been pulled up in
+			 * esp_inbound.
+			 */
+			ASSERT(MBLKL(scratch) >= lastpad + 3);
+
+			/*
+			 * Use "--lastpad" because we already checked the very
+			 * last pad byte previously.
+			 */
+			while (--lastpad != 0) {
+				if (lastpad != *lastbyte) {
+					ipsec_rl_strlog(info.mi_idnum, 0, 0,
+					    SL_ERROR | SL_WARN, "Corrupt ESP "
+					    "packet (bad padding).\n");
+					esp1dbg(("padding not in correct"
+						    " format:\n"));
+					ESP_BUMP_STAT(bad_padding);
+					*counter = &ipdrops_esp_bad_padding;
+					return (B_FALSE);
+				}
+				lastbyte--;
 			}
-			lastval--; last--;
 		}
 	}
 
@@ -2051,7 +2068,7 @@
 	uintptr_t esplen = sizeof (esph_t);
 	uint8_t protocol;
 	ipsa_t *assoc;
-	uint_t iv_len = 0, mac_len = 0;
+	uint_t iv_len, mac_len = 0;
 	uchar_t *icv_buf;
 	udpha_t *udpha;
 	boolean_t is_natt = B_FALSE;
@@ -2148,26 +2165,25 @@
 		esplen += UDPH_SIZE;
 	}
 
-	if (assoc->ipsa_encr_alg != SADB_EALG_NULL)
-		iv_len = assoc->ipsa_iv_len;
-
 	/*
 	 * Set up ESP header and encryption padding for ENCR PI request.
 	 */
 
-	/*
-	 * Determine the padding length.   Pad to 4-bytes.
-	 *
-	 * Include the two additional bytes (hence the - 2) for the padding
-	 * length and the next header.  Take this into account when
-	 * calculating the actual length of the padding.
-	 */
-
+	/* Determine the padding length.  Pad to 4-bytes for no-encryption. */
 	if (assoc->ipsa_encr_alg != SADB_EALG_NULL) {
-		padlen = ((unsigned)(iv_len - datalen - 2)) % iv_len;
+		iv_len = assoc->ipsa_iv_len;
+
+		/*
+		 * Include the two additional bytes (hence the - 2) for the
+		 * padding length and the next header.  Take this into account
+		 * when calculating the actual length of the padding.
+		 */
+		ASSERT(ISP2(iv_len));
+		padlen = ((unsigned)(iv_len - datalen - 2)) & (iv_len - 1);
 	} else {
-		padlen = ((unsigned)(sizeof (uint32_t) - datalen - 2)) %
-		    sizeof (uint32_t);
+		iv_len = 0;
+		padlen = ((unsigned)(sizeof (uint32_t) - datalen - 2)) &
+		    (sizeof (uint32_t) - 1);
 	}
 
 	/* Allocate ESP header and IV. */
--- a/usr/src/uts/common/inet/ip/spd.c	Tue Nov 28 16:45:29 2006 -0800
+++ b/usr/src/uts/common/inet/ip/spd.c	Wed Nov 29 16:09:14 2006 -0800
@@ -63,6 +63,9 @@
 #include <inet/ipsec_info.h>
 #include <inet/sadb.h>
 #include <inet/ipsec_impl.h>
+
+#include <inet/ip_impl.h>	/* For IP_MOD_ID */
+
 #include <inet/ipsecah.h>
 #include <inet/ipsecesp.h>
 #include <inet/ipdrop.h>
@@ -77,8 +80,8 @@
     ipsec_selector_t *);
 static mblk_t *ipsec_apply_global_policy(mblk_t *, conn_t *,
     ipsec_selector_t *);
-static mblk_t *ipsec_check_ipsecin_policy(queue_t *, mblk_t *,
-    ipsec_policy_t *, ipha_t *, ip6_t *, uint64_t);
+static mblk_t *ipsec_check_ipsecin_policy(mblk_t *, ipsec_policy_t *,
+    ipha_t *, ip6_t *, uint64_t);
 static void ipsec_in_release_refs(ipsec_in_t *);
 static void ipsec_out_release_refs(ipsec_out_t *);
 static void ipsec_action_reclaim(void *);
@@ -952,14 +955,13 @@
  *
  */
 void
-ipsec_log_policy_failure(queue_t *q, int type, char *func_name, ipha_t *ipha,
-    ip6_t *ip6h, boolean_t secure)
+ipsec_log_policy_failure(int type, char *func_name, ipha_t *ipha, ip6_t *ip6h,
+    boolean_t secure)
 {
 	char	sbuf[INET6_ADDRSTRLEN];
 	char	dbuf[INET6_ADDRSTRLEN];
 	char	*s;
 	char	*d;
-	short mid = 0;
 
 	ASSERT((ipha == NULL && ip6h != NULL) ||
 	    (ip6h == NULL && ipha != NULL));
@@ -976,13 +978,9 @@
 	/* Always bump the policy failure counter. */
 	ipsec_policy_failure_count[type]++;
 
-	if (q != NULL) {
-		mid = q->q_qinfo->qi_minfo->mi_idnum;
-	}
-	ipsec_rl_strlog(mid, 0, 0, SL_ERROR|SL_WARN|SL_CONSOLE,
-		ipsec_policy_failure_msgs[type],
-		func_name,
-		(secure ? "secure" : "not secure"), s, d);
+	ipsec_rl_strlog(IP_MOD_ID, 0, 0, SL_ERROR|SL_WARN|SL_CONSOLE,
+	    ipsec_policy_failure_msgs[type], func_name,
+	    (secure ? "secure" : "not secure"), s, d);
 }
 
 /*
@@ -1446,13 +1444,12 @@
 }
 
 
-/* ARGSUSED */
 /*
  * Consumes a reference to ipsp.
  */
 static mblk_t *
-ipsec_check_loopback_policy(queue_t *q, mblk_t *first_mp,
-    boolean_t mctl_present, ipsec_policy_t *ipsp)
+ipsec_check_loopback_policy(mblk_t *first_mp, boolean_t mctl_present,
+    ipsec_policy_t *ipsp)
 {
 	mblk_t *ipsec_mp;
 	ipsec_in_t *ii;
@@ -1468,7 +1465,8 @@
 
 	/*
 	 * We should do an actual policy check here.  Revisit this
-	 * when we revisit the IPsec API.
+	 * when we revisit the IPsec API.  (And pass a conn_t in when we
+	 * get there.)
 	 */
 
 	return (first_mp);
@@ -1798,14 +1796,13 @@
  * Consumes a reference to ipsp.
  */
 static mblk_t *
-ipsec_check_ipsecin_policy(queue_t *q, mblk_t *first_mp, ipsec_policy_t *ipsp,
+ipsec_check_ipsecin_policy(mblk_t *first_mp, ipsec_policy_t *ipsp,
     ipha_t *ipha, ip6_t *ip6h, uint64_t pkt_unique)
 {
 	ipsec_in_t *ii;
 	ipsec_action_t *ap;
 	const char *reason = "no policy actions found";
 	mblk_t *data_mp, *ipsec_mp;
-	short mid = 0;
 	kstat_named_t *counter = &ipdrops_spd_got_secure;
 
 	data_mp = first_mp->b_cont;
@@ -1819,7 +1816,7 @@
 	ii = (ipsec_in_t *)ipsec_mp->b_rptr;
 
 	if (ii->ipsec_in_loopback)
-		return (ipsec_check_loopback_policy(q, first_mp, B_TRUE, ipsp));
+		return (ipsec_check_loopback_policy(first_mp, B_TRUE, ipsp));
 	ASSERT(ii->ipsec_in_type == IPSEC_IN);
 	ASSERT(ii->ipsec_in_secure);
 
@@ -1855,10 +1852,7 @@
 		}
 	}
 drop:
-	if (q != NULL) {
-		mid = q->q_qinfo->qi_minfo->mi_idnum;
-	}
-	ipsec_rl_strlog(mid, 0, 0, SL_ERROR|SL_WARN|SL_CONSOLE,
+	ipsec_rl_strlog(IP_MOD_ID, 0, 0, SL_ERROR|SL_WARN|SL_CONSOLE,
 	    "ipsec inbound policy mismatch: %s, packet dropped\n",
 	    reason);
 	IPPOL_REFRELE(ipsp);
@@ -2068,7 +2062,6 @@
 {
 	ipsec_policy_t *p;
 	ipsec_selector_t sel;
-	queue_t *q = NULL;
 	mblk_t *data_mp, *ipsec_mp;
 	boolean_t policy_present;
 	kstat_named_t *counter;
@@ -2096,9 +2089,6 @@
 		return (first_mp);
 	}
 
-	if (connp != NULL)
-		q = CONNP_TO_WQ(connp);
-
 	if (ipsec_mp != NULL) {
 		ASSERT(ipsec_mp->b_datap->db_type == M_CTL);
 		ii = (ipsec_in_t *)(ipsec_mp->b_rptr);
@@ -2126,7 +2116,7 @@
 			 * Technically not a policy mismatch, but it is
 			 * an internal failure.
 			 */
-			ipsec_log_policy_failure(q, IPSEC_POLICY_MISMATCH,
+			ipsec_log_policy_failure(IPSEC_POLICY_MISMATCH,
 			    "ipsec_init_inbound_sel", ipha, ip6h, B_FALSE);
 			counter = &ipdrops_spd_nomem;
 			goto fail;
@@ -2158,14 +2148,15 @@
 			return (first_mp);
 		} else {
 			counter = &ipdrops_spd_got_secure;
-			ipsec_log_policy_failure(q, IPSEC_POLICY_NOT_NEEDED,
+			ipsec_log_policy_failure(IPSEC_POLICY_NOT_NEEDED,
 			    "ipsec_check_global_policy", ipha, ip6h, B_TRUE);
 			goto fail;
 		}
 	}
-	if ((ii != NULL) && (ii->ipsec_in_secure))
-		return (ipsec_check_ipsecin_policy(q, ipsec_mp, p, ipha, ip6h,
-			    pkt_unique));
+	if ((ii != NULL) && (ii->ipsec_in_secure)) {
+		return (ipsec_check_ipsecin_policy(ipsec_mp, p, ipha, ip6h,
+		    pkt_unique));
+	}
 	if (p->ipsp_act->ipa_allow_clear) {
 		BUMP_MIB(&ip_mib, ipsecInSucceeded);
 		IPPOL_REFRELE(p);
@@ -2177,7 +2168,7 @@
 	 * global policy check because the packet was cleartext, and it
 	 * should not have been.
 	 */
-	ipsec_log_policy_failure(q, IPSEC_POLICY_MISMATCH,
+	ipsec_log_policy_failure(IPSEC_POLICY_MISMATCH,
 	    "ipsec_check_global_policy", ipha, ip6h, B_FALSE);
 	counter = &ipdrops_spd_got_clear;
 
@@ -2400,8 +2391,6 @@
 {
 	ipsec_in_t *ii;
 	boolean_t ret;
-	queue_t *q;
-	short mid = 0;
 	mblk_t *mp = mctl_present ? first_mp->b_cont : first_mp;
 	mblk_t *ipsec_mp = mctl_present ? first_mp : NULL;
 	ipsec_latch_t *ipl;
@@ -2433,7 +2422,6 @@
 					return (first_mp);
 				} else {
 					ipsec_log_policy_failure(
-					    CONNP_TO_WQ(connp),
 					    IPSEC_POLICY_MISMATCH,
 					    "ipsec_check_inbound_policy", ipha,
 					    ip6h, B_FALSE);
@@ -2507,11 +2495,7 @@
 			BUMP_MIB(&ip_mib, ipsecInSucceeded);
 			return (first_mp);
 		}
-		q = CONNP_TO_WQ(connp);
-		if (q != NULL) {
-			mid = q->q_qinfo->qi_minfo->mi_idnum;
-		}
-		ipsec_rl_strlog(mid, 0, 0, SL_ERROR|SL_WARN|SL_CONSOLE,
+		ipsec_rl_strlog(IP_MOD_ID, 0, 0, SL_ERROR|SL_WARN|SL_CONSOLE,
 		    "ipsec inbound policy mismatch: %s, packet dropped\n",
 		    reason);
 		ip_drop_packet(first_mp, B_TRUE, NULL, NULL, counter,
@@ -2525,8 +2509,8 @@
 
 	unique_id = conn_to_unique(connp, mp, ipha, ip6h);
 	IPPOL_REFHOLD(ipl->ipl_in_policy);
-	first_mp = ipsec_check_ipsecin_policy(CONNP_TO_WQ(connp), first_mp,
-	    ipl->ipl_in_policy, ipha, ip6h, unique_id);
+	first_mp = ipsec_check_ipsecin_policy(first_mp, ipl->ipl_in_policy,
+	    ipha, ip6h, unique_id);
 	/*
 	 * NOTE: ipsecIn{Failed,Succeeeded} bumped by
 	 * ipsec_check_ipsecin_policy().
@@ -4010,18 +3994,12 @@
     uint8_t proto)
 {
 	mblk_t *ipsec_mp;
-	queue_t *q;
-	short mid = 0;
 
 	ASSERT((pol != NULL) || (connp != NULL));
 
 	ipsec_mp = ipsec_alloc_ipsec_out();
 	if (ipsec_mp == NULL) {
-		q = CONNP_TO_WQ(connp);
-		if (q != NULL) {
-			mid = q->q_qinfo->qi_minfo->mi_idnum;
-		}
-		ipsec_rl_strlog(mid, 0, 0, SL_ERROR|SL_NOTE,
+		ipsec_rl_strlog(IP_MOD_ID, 0, 0, SL_ERROR|SL_NOTE,
 		    "ipsec_attach_ipsec_out: Allocation failure\n");
 		BUMP_MIB(&ip_mib, ipOutDiscards);
 		ip_drop_packet(mp, B_FALSE, NULL, NULL, &ipdrops_spd_nomem,
@@ -5444,8 +5422,8 @@
 		 */
 		IPPOL_REFHOLD(pol);
 
-		if (ipsec_check_ipsecin_policy(NULL, ipsec_mp, pol,
-		    inner_ipv4, inner_ipv6, pkt_unique) != NULL) {
+		if (ipsec_check_ipsecin_policy(ipsec_mp, pol, inner_ipv4,
+		    inner_ipv6, pkt_unique) != NULL) {
 			if (data_tail == NULL) {
 				/* First one */
 				data_chain = data_tail = ipsec_mp->b_cont;
@@ -5504,14 +5482,22 @@
 	ipsec_policy_t *pol;
 	uint16_t tmpport;
 	selret_t rc;
-	boolean_t retval, port_policy_present, is_icmp;
+	boolean_t retval, port_policy_present, is_icmp, global_present;
 	in6_addr_t tmpaddr;
-	uint8_t flags;
+	uint8_t flags, *holder, *outer_hdr;
 
 	sel.ips_is_icmp_inv_acq = 0;
 
-	ASSERT(outer_ipv4 != NULL && outer_ipv6 == NULL ||
-	    outer_ipv4 == NULL && outer_ipv6 != NULL);
+	if (outer_ipv4 != NULL) {
+		ASSERT(outer_ipv6 == NULL);
+		outer_hdr = (uint8_t *)outer_ipv4;
+		global_present = ipsec_inbound_v4_policy_present;
+	} else {
+		outer_hdr = (uint8_t *)outer_ipv6;
+		global_present = ipsec_inbound_v6_policy_present;
+	}
+	ASSERT(outer_hdr != NULL);
+
 	ASSERT(inner_ipv4 != NULL && inner_ipv6 == NULL ||
 	    inner_ipv4 == NULL && inner_ipv6 != NULL);
 	ASSERT(message == *data_mp || message->b_cont == *data_mp);
@@ -5709,9 +5695,7 @@
 	 */
 
 	/* If no per-tunnel security, check global policy now. */
-	if (ipsec_mp != NULL &&
-	    (((outer_ipv4 != NULL) && !ipsec_inbound_v4_policy_present) ||
-		((outer_ipv6 != NULL) && !ipsec_inbound_v6_policy_present))) {
+	if (ipsec_mp != NULL && !global_present) {
 		if (((ipsec_in_t *)(ipsec_mp->b_rptr))->
 		    ipsec_in_icmp_loopback) {
 			/*
@@ -5728,12 +5712,24 @@
 		return (B_FALSE);
 	}
 
+	/*
+	 * The following assertion is valid because only the tun module alters
+	 * the mblk chain - stripping the outer header by advancing mp->b_rptr.
+	 */
+	ASSERT(is_icmp ||
+	    ((*data_mp)->b_datap->db_base <= outer_hdr &&
+		outer_hdr < (*data_mp)->b_rptr));
+	holder = (*data_mp)->b_rptr;
+	(*data_mp)->b_rptr = outer_hdr;
+
 	/* NOTE:  Frees message if it returns NULL. */
 	if (ipsec_check_global_policy(message, NULL, outer_ipv4, outer_ipv6,
 		(ipsec_mp != NULL)) == NULL) {
 		return (B_FALSE);
 	}
 
+	(*data_mp)->b_rptr = holder;
+
 	if (ipsec_mp != NULL)
 		freeb(ipsec_mp);
 
--- a/usr/src/uts/common/inet/ipsec_impl.h	Tue Nov 28 16:45:29 2006 -0800
+++ b/usr/src/uts/common/inet/ipsec_impl.h	Wed Nov 29 16:09:14 2006 -0800
@@ -651,8 +651,7 @@
     boolean_t);
 
 extern boolean_t ipsec_in_to_out(mblk_t *, ipha_t *, ip6_t *);
-extern void ipsec_log_policy_failure(queue_t *, int, char *, ipha_t *,
-		    ip6_t *, boolean_t);
+extern void ipsec_log_policy_failure(int, char *, ipha_t *, ip6_t *, boolean_t);
 extern boolean_t ipsec_inbound_accept_clear(mblk_t *, ipha_t *, ip6_t *);
 extern int ipsec_conn_cache_policy(conn_t *, boolean_t);
 extern mblk_t *ipsec_alloc_ipsec_out(void);
--- a/usr/src/uts/common/inet/tcp/tcp.c	Tue Nov 28 16:45:29 2006 -0800
+++ b/usr/src/uts/common/inet/tcp/tcp.c	Wed Nov 29 16:09:14 2006 -0800
@@ -12082,7 +12082,7 @@
 		if (act == NULL || act->ipa_act.ipa_type == IPSEC_ACT_BYPASS ||
 		    act->ipa_act.ipa_type == IPSEC_ACT_CLEAR)
 			return (B_TRUE);
-		ipsec_log_policy_failure(tcp->tcp_wq, IPSEC_POLICY_MISMATCH,
+		ipsec_log_policy_failure(IPSEC_POLICY_MISMATCH,
 		    "tcp_check_policy", ipha, ip6h, secure);
 		ip_drop_packet(first_mp, B_TRUE, NULL, NULL,
 		    &ipdrops_tcp_clear, &tcp_dropper);
@@ -12093,9 +12093,8 @@
 	 * We have a secure packet.
 	 */
 	if (act == NULL) {
-		ipsec_log_policy_failure(tcp->tcp_wq,
-		    IPSEC_POLICY_NOT_NEEDED, "tcp_check_policy", ipha, ip6h,
-		    secure);
+		ipsec_log_policy_failure(IPSEC_POLICY_NOT_NEEDED,
+		    "tcp_check_policy", ipha, ip6h, secure);
 		ip_drop_packet(first_mp, B_TRUE, NULL, NULL,
 		    &ipdrops_tcp_secure, &tcp_dropper);
 		return (B_FALSE);