diff options
author | pwernau <none@none> | 2007-05-16 17:50:37 -0700 |
---|---|---|
committer | pwernau <none@none> | 2007-05-16 17:50:37 -0700 |
commit | d176106c6c88f9077e61943d95fffc91a84b5214 (patch) | |
tree | ab1543f12b48da23b1046eeeebf1e2ce1ec9bc31 | |
parent | de6613af45a3a6cafa8dd1a4d461de0a305af1c3 (diff) | |
download | illumos-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.c | 4 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/ip6.c | 2 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/spd.c | 47 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/tun.c | 12 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ipsec_impl.h | 6 |
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 *, |