summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpwernau <none@none>2007-05-16 17:50:37 -0700
committerpwernau <none@none>2007-05-16 17:50:37 -0700
commitd176106c6c88f9077e61943d95fffc91a84b5214 (patch)
treeab1543f12b48da23b1046eeeebf1e2ce1ec9bc31
parentde6613af45a3a6cafa8dd1a4d461de0a305af1c3 (diff)
downloadillumos-gate-d176106c6c88f9077e61943d95fffc91a84b5214.tar.gz
6555985 panic in tun_wdata_v4() slowpath case when using per-port IPsec policy
6557246 potential panic with explicit drop policy
-rw-r--r--usr/src/uts/common/inet/ip/ip.c4
-rw-r--r--usr/src/uts/common/inet/ip/ip6.c2
-rw-r--r--usr/src/uts/common/inet/ip/spd.c47
-rw-r--r--usr/src/uts/common/inet/ip/tun.c12
-rw-r--r--usr/src/uts/common/inet/ipsec_impl.h6
5 files changed, 40 insertions, 31 deletions
diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c
index 43432a8f29..60dedabb18 100644
--- a/usr/src/uts/common/inet/ip/ip.c
+++ b/usr/src/uts/common/inet/ip/ip.c
@@ -20416,7 +20416,7 @@ ip_output_options(void *arg, mblk_t *mp, void *arg2, int caller,
* lose the "conn" if we go through ip_newroute.
*/
if (connp->conn_out_enforce_policy || (connp->conn_latch != NULL)) {
- if (((mp = ipsec_attach_ipsec_out(mp, connp, NULL,
+ if (((mp = ipsec_attach_ipsec_out(&mp, connp, NULL,
ipha->ipha_protocol, ipst->ips_netstack)) == NULL)) {
BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards);
if (need_decref)
@@ -20974,7 +20974,7 @@ qnext:
* We need to attach a IPSEC_OUT.
*/
if (connp->conn_out_enforce_policy) {
- if (((mp = ipsec_attach_ipsec_out(mp, connp,
+ if (((mp = ipsec_attach_ipsec_out(&mp, connp,
NULL, ipha->ipha_protocol,
ipst->ips_netstack)) == NULL)) {
BUMP_MIB(&ipst->ips_ip_mib,
diff --git a/usr/src/uts/common/inet/ip/ip6.c b/usr/src/uts/common/inet/ip/ip6.c
index 5f58952058..dc0a9de4e4 100644
--- a/usr/src/uts/common/inet/ip/ip6.c
+++ b/usr/src/uts/common/inet/ip/ip6.c
@@ -9476,7 +9476,7 @@ ip_output_v6(void *arg, mblk_t *mp, void *arg2, int caller)
connp->conn_latch != NULL)) {
ASSERT(first_mp == mp);
/* XXX Any better way to get the protocol fast ? */
- if (((mp = ipsec_attach_ipsec_out(mp, connp, NULL,
+ if (((mp = ipsec_attach_ipsec_out(&mp, connp, NULL,
connp->conn_ulp, ipst->ips_netstack)) == NULL)) {
BUMP_MIB(mibptr, ipIfStatsOutDiscards);
if (need_decref)
diff --git a/usr/src/uts/common/inet/ip/spd.c b/usr/src/uts/common/inet/ip/spd.c
index d1bb4e57ad..8ba551d78a 100644
--- a/usr/src/uts/common/inet/ip/spd.c
+++ b/usr/src/uts/common/inet/ip/spd.c
@@ -77,7 +77,7 @@ static ipsec_act_t *ipsec_act_wildcard_expand(ipsec_act_t *, uint_t *,
netstack_t *);
static void ipsec_out_free(void *);
static void ipsec_in_free(void *);
-static mblk_t *ipsec_attach_global_policy(mblk_t *, conn_t *,
+static mblk_t *ipsec_attach_global_policy(mblk_t **, conn_t *,
ipsec_selector_t *, netstack_t *);
static mblk_t *ipsec_apply_global_policy(mblk_t *, conn_t *,
ipsec_selector_t *, netstack_t *);
@@ -1543,7 +1543,7 @@ ipsec_actvec_free(ipsec_act_t *act, uint_t nact)
* an ipsec_out_t to the packet..
*/
static mblk_t *
-ipsec_attach_global_policy(mblk_t *mp, conn_t *connp, ipsec_selector_t *sel,
+ipsec_attach_global_policy(mblk_t **mp, conn_t *connp, ipsec_selector_t *sel,
netstack_t *ns)
{
ipsec_policy_t *p;
@@ -4241,7 +4241,7 @@ ipsec_alloc_ipsec_out(netstack_t *ns)
* If pol is non-null, we consume a reference to it.
*/
mblk_t *
-ipsec_attach_ipsec_out(mblk_t *mp, conn_t *connp, ipsec_policy_t *pol,
+ipsec_attach_ipsec_out(mblk_t **mp, conn_t *connp, ipsec_policy_t *pol,
uint8_t proto, netstack_t *ns)
{
mblk_t *ipsec_mp;
@@ -4253,13 +4253,17 @@ ipsec_attach_ipsec_out(mblk_t *mp, conn_t *connp, ipsec_policy_t *pol,
if (ipsec_mp == NULL) {
ipsec_rl_strlog(ns, IP_MOD_ID, 0, 0, SL_ERROR|SL_NOTE,
"ipsec_attach_ipsec_out: Allocation failure\n");
- ip_drop_packet(mp, B_FALSE, NULL, NULL,
+ ip_drop_packet(*mp, B_FALSE, NULL, NULL,
DROPPER(ipss, ipds_spd_nomem),
&ipss->ipsec_spd_dropper);
+ *mp = NULL;
return (NULL);
}
- ipsec_mp->b_cont = mp;
- return (ipsec_init_ipsec_out(ipsec_mp, connp, pol, proto, ns));
+ ipsec_mp->b_cont = *mp;
+ /*
+ * If *mp is NULL, ipsec_init_ipsec_out() won't/should not be using it.
+ */
+ return (ipsec_init_ipsec_out(ipsec_mp, mp, connp, pol, proto, ns));
}
/*
@@ -4269,22 +4273,18 @@ ipsec_attach_ipsec_out(mblk_t *mp, conn_t *connp, ipsec_policy_t *pol,
* If pol is non-null, we consume a reference to it.
*/
mblk_t *
-ipsec_init_ipsec_out(mblk_t *ipsec_mp, conn_t *connp, ipsec_policy_t *pol,
- uint8_t proto, netstack_t *ns)
+ipsec_init_ipsec_out(mblk_t *ipsec_mp, mblk_t **mp, conn_t *connp,
+ ipsec_policy_t *pol, uint8_t proto, netstack_t *ns)
{
- mblk_t *mp;
ipsec_out_t *io;
ipsec_policy_t *p;
ipha_t *ipha;
ip6_t *ip6h;
ipsec_stack_t *ipss = ns->netstack_ipsec;
- ASSERT((pol != NULL) || (connp != NULL));
+ ASSERT(ipsec_mp->b_cont == *mp);
- /*
- * If mp is NULL, we won't/should not be using it.
- */
- mp = ipsec_mp->b_cont;
+ ASSERT((pol != NULL) || (connp != NULL));
ASSERT(ipsec_mp->b_datap->db_type == M_CTL);
ASSERT(ipsec_mp->b_wptr == (ipsec_mp->b_rptr + sizeof (ipsec_info_t)));
@@ -4302,8 +4302,8 @@ ipsec_init_ipsec_out(mblk_t *ipsec_mp, conn_t *connp, ipsec_policy_t *pol,
io->ipsec_out_ns = ns; /* No netstack_hold */
- if (mp != NULL) {
- ipha = (ipha_t *)mp->b_rptr;
+ if (*mp != NULL) {
+ ipha = (ipha_t *)(*mp)->b_rptr;
if (IPH_HDR_VERSION(ipha) == IP_VERSION) {
io->ipsec_out_v4 = B_TRUE;
ip6h = NULL;
@@ -4350,9 +4350,11 @@ ipsec_init_ipsec_out(mblk_t *ipsec_mp, conn_t *connp, ipsec_policy_t *pol,
* it from the packet.
*/
- if (!ipsec_init_outbound_ports(&sel, mp, ipha, ip6h, 0,
+ if (!ipsec_init_outbound_ports(&sel, *mp, ipha, ip6h, 0,
ns->netstack_ipsec)) {
- /* Callee did ip_drop_packet(). */
+ /* Callee did ip_drop_packet() on *mp. */
+ *mp = NULL;
+ freeb(ipsec_mp);
return (NULL);
}
io->ipsec_out_src_port = sel.ips_local_port;
@@ -4383,6 +4385,7 @@ ipsec_init_ipsec_out(mblk_t *ipsec_mp, conn_t *connp, ipsec_policy_t *pol,
ip_drop_packet(ipsec_mp, B_FALSE, NULL, NULL,
DROPPER(ipss, ipds_spd_explicit),
&ipss->ipsec_spd_dropper);
+ *mp = NULL;
ipsec_mp = NULL;
}
}
@@ -4672,7 +4675,13 @@ ip_wput_attach_policy(mblk_t *ipsec_mp, ipha_t *ipha, ip6_t *ip6h, ire_t *ire,
ASSERT(io->ipsec_out_need_policy == B_FALSE);
return (ipsec_mp);
}
- ipsec_mp = ipsec_attach_global_policy(mp, connp, &sel, ns);
+ /*
+ * We pass in a pointer to a pointer because mp can become
+ * NULL due to allocation failures or explicit drops. Callers
+ * of this function should assume a NULL mp means the packet
+ * was dropped.
+ */
+ ipsec_mp = ipsec_attach_global_policy(&mp, connp, &sel, ns);
if (ipsec_mp == NULL)
return (mp);
diff --git a/usr/src/uts/common/inet/ip/tun.c b/usr/src/uts/common/inet/ip/tun.c
index 805af0164c..fbf9138d9e 100644
--- a/usr/src/uts/common/inet/ip/tun.c
+++ b/usr/src/uts/common/inet/ip/tun.c
@@ -4683,6 +4683,7 @@ tun_wdata_v4(queue_t *q, mblk_t *mp)
switch (atp->tun_flags & TUN_LOWER_MASK) {
case TUN_L_V4:
+ hdrlen = IPH_HDR_LENGTH(&atp->tun_ipha);
if (inner_ipha->ipha_dst == atp->tun_ipha.ipha_dst) {
/*
* Watch out! There is potential for an infinite loop.
@@ -4702,11 +4703,10 @@ tun_wdata_v4(queue_t *q, mblk_t *mp)
}
/* room for IPv4 header? */
- if ((mp->b_rptr - mp->b_datap->db_base) < sizeof (ipha_t)) {
+ if ((mp->b_rptr - mp->b_datap->db_base) < hdrlen) {
/* no */
- nmp = allocb(sizeof (ipha_t) + atp->tun_extra_offset,
- BPRI_HI);
+ nmp = allocb(hdrlen + atp->tun_extra_offset, BPRI_HI);
if (nmp == NULL) {
atomic_add_32(&atp->tun_OutDiscard, 1);
atomic_add_32(&atp->tun_allocbfail, 1);
@@ -4716,10 +4716,10 @@ tun_wdata_v4(queue_t *q, mblk_t *mp)
nmp->b_cont = mp;
mp = nmp;
mp->b_wptr = mp->b_datap->db_lim;
- mp->b_rptr = mp->b_wptr - sizeof (ipha_t);
+ mp->b_rptr = mp->b_wptr - hdrlen;
} else {
/* yes */
- mp->b_rptr -= sizeof (ipha_t);
+ mp->b_rptr -= hdrlen;
}
outer_ipha = (ipha_t *)mp->b_rptr;
@@ -4728,7 +4728,7 @@ tun_wdata_v4(queue_t *q, mblk_t *mp)
*/
*outer_ipha = atp->tun_ipha;
outer_ipha->ipha_length = htons(ntohs(inner_ipha->ipha_length)
- + sizeof (ipha_t));
+ + hdrlen);
/*
* copy the tos from inner header. We mask off
* ECN bits (bits 6 and 7) because there is currently no
diff --git a/usr/src/uts/common/inet/ipsec_impl.h b/usr/src/uts/common/inet/ipsec_impl.h
index bc576a8deb..2c40bf1f70 100644
--- a/usr/src/uts/common/inet/ipsec_impl.h
+++ b/usr/src/uts/common/inet/ipsec_impl.h
@@ -786,10 +786,10 @@ 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(netstack_t *);
-extern mblk_t *ipsec_attach_ipsec_out(mblk_t *, conn_t *, ipsec_policy_t *,
- uint8_t, netstack_t *);
-extern mblk_t *ipsec_init_ipsec_out(mblk_t *, conn_t *, ipsec_policy_t *,
+extern mblk_t *ipsec_attach_ipsec_out(mblk_t **, conn_t *, ipsec_policy_t *,
uint8_t, netstack_t *);
+extern mblk_t *ipsec_init_ipsec_out(mblk_t *, mblk_t **, conn_t *,
+ ipsec_policy_t *, uint8_t, netstack_t *);
struct ipsec_in_s;
extern ipsec_action_t *ipsec_in_to_out_action(struct ipsec_in_s *);
extern boolean_t ipsec_check_ipsecin_latch(struct ipsec_in_s *, mblk_t *,