Abstract out the location of an m_tag's data by adding a m_tag_data() inline.
authorMatthew Dillon <dillon@dragonflybsd.org>
Fri, 17 Jun 2005 19:12:23 +0000 (19:12 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Fri, 17 Jun 2005 19:12:23 +0000 (19:12 +0000)
Replace all instances of 'mtag + 1' with the new inline.

Fix numerous bugs, mainly in ipfw/ipfw2, where the m_tag data was being stored
in the wrong place and corrupting the m_tag, resulting in a panic.  This
primarily occured with the use of divert rules.

Reported-by: Ben Woolley <tautolog@gmail.com>
14 files changed:
sys/kern/uipc_mbuf2.c
sys/net/ipfw/ip_fw.c
sys/net/ipfw/ip_fw2.c
sys/netinet/ip_divert.c
sys/netinet/ip_encap.c
sys/netinet/ip_input.c
sys/netinet/ip_output.c
sys/netinet6/ip6_input.c
sys/netinet6/ipsec.c
sys/netproto/ipsec/ipsec_input.c
sys/netproto/ipsec/ipsec_output.c
sys/netproto/ipsec/xform_ah.c
sys/netproto/ipsec/xform_esp.c
sys/sys/mbuf.h

index 90bb5ea..ee7c3dd 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/kern/uipc_mbuf2.c,v 1.2.2.5 2003/01/23 21:06:44 sam Exp $     */
-/*     $DragonFly: src/sys/kern/uipc_mbuf2.c,v 1.10 2005/06/07 19:08:55 hsu Exp $      */
+/*     $DragonFly: src/sys/kern/uipc_mbuf2.c,v 1.11 2005/06/17 19:12:16 dillon Exp $   */
 /*     $KAME: uipc_mbuf2.c,v 1.31 2001/11/28 11:08:53 itojun Exp $     */
 /*     $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $   */
 
@@ -294,6 +294,7 @@ void
 m_tag_prepend(struct mbuf *m, struct m_tag *t)
 {
        KASSERT(m && t, ("m_tag_prepend: null argument, m %p t %p", m, t));
+       KASSERT(m->m_flags & M_PKTHDR, ("m_tag_prepend: mbuf %p non-header", m));
        SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
 }
 
@@ -302,6 +303,7 @@ void
 m_tag_unlink(struct mbuf *m, struct m_tag *t)
 {
        KASSERT(m && t, ("m_tag_unlink: null argument, m %p t %p", m, t));
+       KASSERT(m->m_flags & M_PKTHDR, ("m_tag_unlink: mbuf %p non-header", m));
        SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
 }
 
@@ -310,6 +312,7 @@ void
 m_tag_delete(struct mbuf *m, struct m_tag *t)
 {
        KASSERT(m && t, ("m_tag_delete: null argument, m %p t %p", m, t));
+       KASSERT(m->m_flags & M_PKTHDR, ("m_tag_delete: mbuf %p non-header", m));
        m_tag_unlink(m, t);
        m_tag_free(t);
 }
@@ -321,6 +324,7 @@ m_tag_delete_chain(struct mbuf *m)
        struct m_tag *p, *q;
 
        KASSERT(m, ("m_tag_delete_chain: null mbuf"));
+       KASSERT(m->m_flags & M_PKTHDR, ("m_tag_delete_chain: mbuf %p non-header", m));
        p = SLIST_FIRST(&m->m_pkthdr.tags);
        if (p == NULL)
                return;
index 90d29da..9510ba8 100644 (file)
@@ -14,7 +14,7 @@
  * This software is provided ``AS IS'' without any warranties of any kind.
  *
  * $FreeBSD: src/sys/netinet/ip_fw.c,v 1.131.2.39 2003/01/20 02:23:07 iedowse Exp $
- * $DragonFly: src/sys/net/ipfw/Attic/ip_fw.c,v 1.13 2005/06/15 18:46:54 joerg Exp $
+ * $DragonFly: src/sys/net/ipfw/Attic/ip_fw.c,v 1.14 2005/06/17 19:12:19 dillon Exp $
  */
 
 #define        DEB(x)
@@ -1113,7 +1113,7 @@ ip_fw_chk(struct ip_fw_args *args)
 
        /* Grab and reset cookie */
        if ((mtag = m_tag_find(*m, PACKET_TAG_IPFW_DIVERT, NULL)) != NULL) {
-               skipto = *(u_int16_t *)(mtag + 1);
+               skipto = *(u_int16_t *)m_tag_data(mtag);
                m_tag_delete(*m, mtag);
                mtag = NULL;
        } else {
@@ -1493,18 +1493,18 @@ got_match:
 #ifdef IPDIVERT
                case IP_FW_F_DIVERT:
                        mtag = m_tag_get(PACKET_TAG_IPFW_DIVERT,
-                           sizeof(u_int16_t), M_NOWAIT);
+                                       sizeof(u_int16_t), M_NOWAIT);
                        if (mtag == NULL)
                                goto dropit;
-                       *(u_int16_t *)mtag = f->fw_number;
+                       *(u_int16_t *)m_tag_data(mtag) = f->fw_number;
                        m_tag_prepend(*m, mtag);
                        return(f->fw_divert_port);
                case IP_FW_F_TEE:
                        mtag = m_tag_get(PACKET_TAG_IPFW_DIVERT,
-                           sizeof(u_int16_t), M_NOWAIT);
+                                       sizeof(u_int16_t), M_NOWAIT);
                        if (mtag == NULL)
                                goto dropit;
-                       *(u_int16_t *)mtag = f->fw_number;
+                       *(u_int16_t *)m_tag_data(mtag) = f->fw_number;
                        m_tag_prepend(*m, mtag);
                        return(f->fw_divert_port | IP_FW_PORT_TEE_FLAG);
 #endif
index 7719e5f..0a924a8 100644 (file)
@@ -23,7 +23,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/netinet/ip_fw2.c,v 1.6.2.12 2003/04/08 10:42:32 maxim Exp $
- * $DragonFly: src/sys/net/ipfw/ip_fw2.c,v 1.16 2005/06/15 18:46:54 joerg Exp $
+ * $DragonFly: src/sys/net/ipfw/ip_fw2.c,v 1.17 2005/06/17 19:12:19 dillon Exp $
  */
 
 #define        DEB(x)
@@ -1404,7 +1404,7 @@ after_ip_checks:
 
                mtag = m_tag_find(m, PACKET_TAG_IPFW_DIVERT, NULL);
                if (mtag != NULL)
-                       skipto = *(u_int16_t *)(mtag + 1);
+                       skipto = *(u_int16_t *)m_tag_data(mtag);
                else
                        skipto = 0;
 
@@ -1859,12 +1859,12 @@ check_body:
                                        break;
 
                                mtag = m_tag_get(PACKET_TAG_IPFW_DIVERT,
-                                   sizeof(u_int16_t), M_NOWAIT);
+                                               sizeof(u_int16_t), M_NOWAIT);
                                if (mtag == NULL) {
                                        retval = IP_FW_PORT_DENY_FLAG;
                                        goto done;
                                }
-                               *(u_int16_t *)mtag = f->rulenum;
+                               *(u_int16_t *)m_tag_data(mtag) = f->rulenum;
                                m_tag_prepend(m, mtag);
                                retval = (cmd->opcode == O_DIVERT) ?
                                    cmd->arg1 :
index d33d134..77f3f48 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/netinet/ip_divert.c,v 1.42.2.6 2003/01/23 21:06:45 sam Exp $
- * $DragonFly: src/sys/netinet/ip_divert.c,v 1.24 2005/06/02 23:52:42 dillon Exp $
+ * $DragonFly: src/sys/netinet/ip_divert.c,v 1.25 2005/06/17 19:12:20 dillon Exp $
  */
 
 #include "opt_inet.h"
@@ -158,7 +158,7 @@ divert_packet(struct mbuf *m, int incoming, int port)
        KASSERT(port != 0, ("%s: port=0", __func__));
 
        if ((mtag = m_tag_find(m, PACKET_TAG_IPFW_DIVERT, NULL)) != NULL)
-               divsrc.sin_port = *(u_int16_t *)(mtag + 1);
+               divsrc.sin_port = *(u_int16_t *)m_tag_data(mtag);
        else
                divsrc.sin_port = 0;
 
@@ -272,7 +272,7 @@ div_output(struct socket *so, struct mbuf *m,
        if (sin) {
                int i;
 
-               *(u_int16_t *)mtag = sin->sin_port;
+               *(u_int16_t *)m_tag_data(mtag) = sin->sin_port;
                /*
                 * Find receive interface with the given name, stuffed
                 * (if it exists) in the sin_zero[] field.
@@ -283,6 +283,8 @@ div_output(struct socket *so, struct mbuf *m,
                        ;
                if ( i > 0 && i < sizeof sin->sin_zero)
                        m->m_pkthdr.rcvif = ifunit(sin->sin_zero);
+       } else {
+               *(u_int16_t *)m_tag_data(mtag) = 0;
        }
 
        /* Reinject packet into the system as incoming or outgoing */
index 699e554..637a8b6 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet/ip_encap.c,v 1.1.2.5 2003/01/23 21:06:45 sam Exp $    */
-/*     $DragonFly: src/sys/netinet/ip_encap.c,v 1.12 2005/06/02 23:52:42 dillon Exp $  */
+/*     $DragonFly: src/sys/netinet/ip_encap.c,v 1.13 2005/06/17 19:12:20 dillon Exp $  */
 /*     $KAME: ip_encap.c,v 1.41 2001/03/15 08:35:08 itojun Exp $       */
 
 /*
@@ -497,7 +497,7 @@ encap_fillarg(m, ep)
 
        tag = m_tag_get(PACKET_TAG_ENCAP, sizeof(void *), MB_DONTWAIT);
        if (tag != NULL) {
-               *(void **)(tag + 1) = ep->arg;
+               *(void **)m_tag_data(tag) = ep->arg;
                m_tag_prepend(m, tag);
        }
 }
@@ -511,7 +511,7 @@ encap_getarg(m)
 
        tag = m_tag_find(m, PACKET_TAG_ENCAP, NULL);
        if (tag != NULL) {
-               p = *(void **)(tag + 1);
+               p = *(void **)m_tag_data(tag);
                m_tag_delete(m, tag);
        }
        return p;
index b22603c..1353dd8 100644 (file)
@@ -82,7 +82,7 @@
  *
  *     @(#)ip_input.c  8.2 (Berkeley) 1/4/94
  * $FreeBSD: src/sys/netinet/ip_input.c,v 1.130.2.52 2003/03/07 07:01:28 silby Exp $
- * $DragonFly: src/sys/netinet/ip_input.c,v 1.54 2005/06/08 23:45:00 hsu Exp $
+ * $DragonFly: src/sys/netinet/ip_input.c,v 1.55 2005/06/17 19:12:20 dillon Exp $
  */
 
 #define        _IP_VHL
@@ -836,7 +836,7 @@ pass:
                mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
                crit_enter();
                if (mtag != NULL) {
-                       tdbi = (struct tdb_ident *)(mtag + 1);
+                       tdbi = (struct tdb_ident *)m_tag_data(mtag);
                        sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND);
                } else {
                        sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
@@ -1063,7 +1063,7 @@ found:
                mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
                crit_enter();
                if (mtag != NULL) {
-                       tdbi = (struct tdb_ident *)(mtag + 1);
+                       tdbi = (struct tdb_ident *)m_tag_data(mtag);
                        sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND);
                } else {
                        sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
index 6d420cb..b640e94 100644 (file)
@@ -28,7 +28,7 @@
  *
  *     @(#)ip_output.c 8.3 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/netinet/ip_output.c,v 1.99.2.37 2003/04/15 06:44:45 silby Exp $
- * $DragonFly: src/sys/netinet/ip_output.c,v 1.30 2005/06/09 02:03:38 hsu Exp $
+ * $DragonFly: src/sys/netinet/ip_output.c,v 1.31 2005/06/17 19:12:20 dillon Exp $
  */
 
 #define _IP_VHL
@@ -585,7 +585,7 @@ skip_ipsec:
        mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL);
        crit_enter();
        if (mtag != NULL) {
-               tdbi = (struct tdb_ident *)(mtag + 1);
+               tdbi = (struct tdb_ident *)m_tag_data(mtag);
                sp = ipsec_getpolicy(tdbi, IPSEC_DIR_OUTBOUND);
                if (sp == NULL)
                        error = -EINVAL;        /* force silent drop */
@@ -619,7 +619,7 @@ skip_ipsec:
                         */
                        if (sp->req->sav == NULL)
                                break;
-                       tdbi = (struct tdb_ident *)(mtag + 1);
+                       tdbi = (struct tdb_ident *)m_tag_data(mtag);
                        if (tdbi->spi == sp->req->sav->spi &&
                            tdbi->proto == sp->req->sav->sah->saidx.proto &&
                            bcmp(&tdbi->dst, &sp->req->sav->sah->saidx.dst,
@@ -686,7 +686,7 @@ skip_ipsec:
                mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL);
                if (mtag != NULL && !(ifp->if_capenable & IFCAP_IPSEC)) {
                        /* notify IPsec to do its own crypto */
-                       ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
+                       ipsp_skipcrypto_unmark((struct tdb_ident *)m_tag_data(mtag));
                        error = EHOSTUNREACH;
                        goto bad;
                }
index dd9b2b9..72ad0d0 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/ip6_input.c,v 1.11.2.15 2003/01/24 05:11:35 sam Exp $        */
-/*     $DragonFly: src/sys/netinet6/ip6_input.c,v 1.25 2005/02/11 22:25:57 joerg Exp $ */
+/*     $DragonFly: src/sys/netinet6/ip6_input.c,v 1.26 2005/06/17 19:12:22 dillon Exp $        */
 /*     $KAME: ip6_input.c,v 1.259 2002/01/21 04:58:09 jinmei Exp $     */
 
 /*
@@ -1577,8 +1577,8 @@ ip6_addaux(struct mbuf *m)
                        m_tag_prepend(m, tag);
        }
        if (tag)
-               bzero(tag+1, sizeof (struct ip6aux));
-       return tag ? (struct ip6aux*)(tag+1) : NULL;
+               bzero(m_tag_data(tag), sizeof (struct ip6aux));
+       return tag ? (struct ip6aux *)m_tag_data(tag) : NULL;
 }
 
 struct ip6aux *
index 4222998..05a6986 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netinet6/ipsec.c,v 1.3.2.12 2003/05/06 06:46:58 suz Exp $     */
-/*     $DragonFly: src/sys/netinet6/ipsec.c,v 1.12 2005/06/03 19:56:08 eirikn Exp $    */
+/*     $DragonFly: src/sys/netinet6/ipsec.c,v 1.13 2005/06/17 19:12:22 dillon Exp $    */
 /*     $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */
 
 /*
@@ -3348,7 +3348,7 @@ ipsec_addhist(struct mbuf *m, int proto, u_int32_t spi)
                        sizeof (struct ipsec_history), M_NOWAIT);
        if (tag == NULL)
                return ENOBUFS;
-       p = (struct ipsec_history *)(tag+1);
+       p = (struct ipsec_history *)m_tag_data(tag);
        bzero(p, sizeof(*p));
        p->ih_proto = proto;
        p->ih_spi = spi;
index 8044eda..8d3847e 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netipsec/ipsec_input.c,v 1.2.4.2 2003/03/28 20:32:53 sam Exp $        */
-/*     $DragonFly: src/sys/netproto/ipsec/ipsec_input.c,v 1.8 2005/06/10 23:59:31 dillon Exp $ */
+/*     $DragonFly: src/sys/netproto/ipsec/ipsec_input.c,v 1.9 2005/06/17 19:12:23 dillon Exp $ */
 /*     $OpenBSD: ipsec_input.c,v 1.63 2003/02/20 18:35:43 deraadt Exp $        */
 /*
  * The authors of this code are John Ioannidis (ji@tla.org),
@@ -385,7 +385,7 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
         */
        if (mt == NULL && sproto != IPPROTO_IPCOMP) {
                mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
-                   sizeof(struct tdb_ident), M_NOWAIT);
+                               sizeof(struct tdb_ident), M_NOWAIT);
                if (mtag == NULL) {
                        DPRINTF(("ipsec4_common_input_cb: failed to get tag\n"));
                        IPSEC_ISTAT(sproto, espstat.esps_hdrops,
@@ -394,7 +394,7 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
                        goto bad;
                }
 
-               tdbi = (struct tdb_ident *)(mtag + 1);
+               tdbi = (struct tdb_ident *)m_tag_data(mtag);
                bcopy(&saidx->dst, &tdbi->dst, saidx->dst.sa.sa_len);
                tdbi->proto = sproto;
                tdbi->spi = sav->spi;
@@ -692,7 +692,7 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto
         */
        if (mt == NULL && sproto != IPPROTO_IPCOMP) {
                mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
-                   sizeof(struct tdb_ident), M_NOWAIT);
+                               sizeof(struct tdb_ident), M_NOWAIT);
                if (mtag == NULL) {
                        DPRINTF(("ipsec_common_input_cb: failed to "
                            "get tag\n"));
@@ -702,7 +702,7 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto
                        goto bad;
                }
 
-               tdbi = (struct tdb_ident *)(mtag + 1);
+               tdbi = (struct tdb_ident *)m_tag_data(mtag);
                bcopy(&saidx->dst, &tdbi->dst, sizeof(union sockaddr_union));
                tdbi->proto = sproto;
                tdbi->spi = sav->spi;
index bb0b205..f9529cb 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/netipsec/ipsec_output.c,v 1.3.2.2 2003/03/28 20:32:53 sam Exp $
- * $DragonFly: src/sys/netproto/ipsec/ipsec_output.c,v 1.8 2005/06/10 23:59:31 dillon Exp $
+ * $DragonFly: src/sys/netproto/ipsec/ipsec_output.c,v 1.9 2005/06/17 19:12:23 dillon Exp $
  */
 
 /*
@@ -138,7 +138,7 @@ ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
                goto bad;
        }
 
-       tdbi = (struct tdb_ident *)(mtag + 1);
+       tdbi = (struct tdb_ident *)m_tag_data(mtag);
        tdbi->dst = saidx->dst;
        tdbi->proto = saidx->proto;
        tdbi->spi = sav->spi;
index 75ee80a..106fa73 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netipsec/xform_ah.c,v 1.1.4.2 2003/02/26 00:14:05 sam Exp $   */
-/*     $DragonFly: src/sys/netproto/ipsec/xform_ah.c,v 1.7 2005/06/10 23:59:31 dillon Exp $    */
+/*     $DragonFly: src/sys/netproto/ipsec/xform_ah.c,v 1.8 2005/06/17 19:12:23 dillon Exp $    */
 /*     $OpenBSD: ip_ah.c,v 1.63 2001/06/26 06:18:58 angelos Exp $ */
 /*
  * The authors of this code are John Ioannidis (ji@tla.org),
@@ -631,7 +631,7 @@ ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
        for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, NULL);
             mtag != NULL;
             mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, mtag)) {
-               tdbi = (struct tdb_ident *) (mtag + 1);
+               tdbi = (struct tdb_ident *)m_tag_data(mtag);
                if (tdbi->proto == sav->sah->saidx.proto &&
                    tdbi->spi == sav->spi &&
                    !bcmp(&tdbi->dst, &sav->sah->saidx.dst,
index 1e97726..619c40b 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/sys/netipsec/xform_esp.c,v 1.2.2.2 2003/02/26 00:14:05 sam Exp $  */
-/*     $DragonFly: src/sys/netproto/ipsec/xform_esp.c,v 1.7 2005/06/10 23:59:31 dillon Exp $   */
+/*     $DragonFly: src/sys/netproto/ipsec/xform_esp.c,v 1.8 2005/06/17 19:12:23 dillon Exp $   */
 /*     $OpenBSD: ip_esp.c,v 1.69 2001/06/26 06:18:59 angelos Exp $ */
 /*
  * The authors of this code are John Ioannidis (ji@tla.org),
@@ -331,7 +331,7 @@ esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
        for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, NULL);
             mtag != NULL;
             mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, mtag)) {
-               tdbi = (struct tdb_ident *) (mtag + 1);
+               tdbi = (struct tdb_ident *)m_tag_data(mtag);
                if (tdbi->proto == sav->sah->saidx.proto &&
                    tdbi->spi == sav->spi &&
                    !bcmp(&tdbi->dst, &sav->sah->saidx.dst,
index 79227e6..d917a5e 100644 (file)
@@ -34,7 +34,7 @@
  *
  *     @(#)mbuf.h      8.5 (Berkeley) 2/19/95
  * $FreeBSD: src/sys/sys/mbuf.h,v 1.44.2.17 2003/04/15 06:15:02 silby Exp $
- * $DragonFly: src/sys/sys/mbuf.h,v 1.30 2005/06/10 23:59:33 dillon Exp $
+ * $DragonFly: src/sys/sys/mbuf.h,v 1.31 2005/06/17 19:12:18 dillon Exp $
  */
 
 #ifndef _SYS_MBUF_H_
@@ -559,6 +559,12 @@ struct     m_tag   *m_tag_next(struct mbuf *, struct m_tag *);
 /* these are for openbsd compatibility */
 #define        MTAG_ABI_COMPAT         0               /* compatibility ABI */
 
+static __inline void *
+m_tag_data(struct m_tag *tag)
+{
+       return ((void *)(tag + 1));
+}
+
 static __inline struct m_tag *
 m_tag_get(int type, int length, int wait)
 {