Source-Changes-HG archive

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

[src/trunk]: src/sys/net/npf Change npf_cache_all so that it ensures the pote...



details:   https://anonhg.NetBSD.org/src/rev/33d02f30f2a5
branches:  trunk
changeset: 321549:33d02f30f2a5
user:      maxv <maxv%NetBSD.org@localhost>
date:      Thu Mar 22 08:57:47 2018 +0000

description:
Change npf_cache_all so that it ensures the potential ICMP Query Id is in
the nbuf. In such a way that we don't need to ensure that later.

Change npfa_icmp4_inspect and npfa_icmp6_inspect so that they touch neither
the nbuf nor npc. Adapt their callers accordingly.

In the end, if a packet has a Query Id, we set NPC_ICMP_ID in npc and leave
right away, without recaching npc (not needed since we didn't touch the
nbuf).

This fixes the handling of Query Id packets (that I broke in my previous
commit), and also fixes another possible use-after-free.

diffstat:

 sys/net/npf/npf_alg_icmp.c |  70 ++++++++++++++++++++++++++-------------------
 sys/net/npf/npf_inet.c     |  13 +++++--
 2 files changed, 50 insertions(+), 33 deletions(-)

diffs (230 lines):

diff -r 09641237b2b5 -r 33d02f30f2a5 sys/net/npf/npf_alg_icmp.c
--- a/sys/net/npf/npf_alg_icmp.c        Thu Mar 22 07:32:07 2018 +0000
+++ b/sys/net/npf/npf_alg_icmp.c        Thu Mar 22 08:57:47 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: npf_alg_icmp.c,v 1.27 2018/03/22 07:32:07 maxv Exp $   */
+/*     $NetBSD: npf_alg_icmp.c,v 1.28 2018/03/22 08:57:47 maxv Exp $   */
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
 
 #ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.27 2018/03/22 07:32:07 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.28 2018/03/22 08:57:47 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/module.h>
@@ -120,13 +120,15 @@
 /*
  * npfa_icmp{4,6}_inspect: retrieve unique identifiers - either ICMP query
  * ID or TCP/UDP ports of the original packet, which is embedded.
+ *
+ * => Sets hasqid=true if the packet has a Query Id. In this case neither
+ *    the nbuf nor npc is touched.
  */
 
 static bool
-npfa_icmp4_inspect(const int type, npf_cache_t *npc)
+npfa_icmp4_inspect(const int type, npf_cache_t *npc, bool *hasqid)
 {
        nbuf_t *nbuf = npc->npc_nbuf;
-       u_int offby;
 
        /* Per RFC 792. */
        switch (type) {
@@ -147,12 +149,8 @@
        case ICMP_TSTAMPREPLY:
        case ICMP_IREQ:
        case ICMP_IREQREPLY:
-               /* Should contain ICMP query ID - ensure. */
-               offby = offsetof(struct icmp, icmp_id);
-               if (!nbuf_advance(nbuf, offby, sizeof(uint16_t))) {
-                       return false;
-               }
-               npc->npc_info |= NPC_ICMP_ID;
+               /* Contains ICMP query ID. */
+               *hasqid = true;
                return true;
        default:
                break;
@@ -161,10 +159,9 @@
 }
 
 static bool
-npfa_icmp6_inspect(const int type, npf_cache_t *npc)
+npfa_icmp6_inspect(const int type, npf_cache_t *npc, bool *hasqid)
 {
        nbuf_t *nbuf = npc->npc_nbuf;
-       u_int offby;
 
        /* Per RFC 4443. */
        switch (type) {
@@ -180,12 +177,8 @@
 
        case ICMP6_ECHO_REQUEST:
        case ICMP6_ECHO_REPLY:
-               /* Should contain ICMP query ID - ensure. */
-               offby = offsetof(struct icmp6_hdr, icmp6_id);
-               if (!nbuf_advance(nbuf, offby, sizeof(uint16_t))) {
-                       return false;
-               }
-               npc->npc_info |= NPC_ICMP_ID;
+               /* Contains ICMP query ID. */
+               *hasqid = true;
                return true;
        default:
                break;
@@ -196,13 +189,13 @@
 /*
  * npfa_icmp_inspect: ALG ICMP inspector.
  *
- * => Returns true if "enpc" is filled.
+ * => Returns false if there is a problem with the format.
  */
 static bool
 npfa_icmp_inspect(npf_cache_t *npc, npf_cache_t *enpc)
 {
        nbuf_t *nbuf = npc->npc_nbuf;
-       bool ret;
+       bool ret, hasqid = false;
 
        KASSERT(npf_iscached(npc, NPC_IP46));
        KASSERT(npf_iscached(npc, NPC_ICMP));
@@ -222,10 +215,10 @@
         */
        if (npf_iscached(npc, NPC_IP4)) {
                const struct icmp *ic = npc->npc_l4.icmp;
-               ret = npfa_icmp4_inspect(ic->icmp_type, enpc);
+               ret = npfa_icmp4_inspect(ic->icmp_type, enpc, &hasqid);
        } else if (npf_iscached(npc, NPC_IP6)) {
                const struct icmp6_hdr *ic6 = npc->npc_l4.icmp6;
-               ret = npfa_icmp6_inspect(ic6->icmp6_type, enpc);
+               ret = npfa_icmp6_inspect(ic6->icmp6_type, enpc, &hasqid);
        } else {
                ret = false;
        }
@@ -234,12 +227,10 @@
        }
 
        /* ICMP ID is the original packet, just indicate it. */
-       if (npf_iscached(enpc, NPC_ICMP_ID)) {
+       if (hasqid) {
                npc->npc_info |= NPC_ICMP_ID;
-               return false;
        }
 
-       /* Indicate that embedded packet is in the cache. */
        return true;
 }
 
@@ -248,6 +239,7 @@
 {
        npf_conn_t *conn = NULL;
        npf_cache_t enpc;
+       bool hasqid = false;
 
        /* Inspect ICMP packet for an embedded packet. */
        if (!npf_iscached(npc, NPC_ICMP))
@@ -256,6 +248,15 @@
                goto out;
 
        /*
+        * If the ICMP packet had a Query Id, leave now. The packet didn't get
+        * modified, so no need to recache npc.
+        */
+       if (npf_iscached(npc, NPC_ICMP_ID)) {
+               KASSERT(!nbuf_flag_p(nbuf, NBUF_DATAREF_RESET));
+               return NULL;
+       }
+
+       /*
         * Invert the identifiers of the embedded packet.
         * If it is ICMP, then ensure ICMP ID.
         */
@@ -281,16 +282,18 @@
                break;
        case IPPROTO_ICMP: {
                const struct icmp *ic = enpc.npc_l4.icmp;
-               ret = npfa_icmp4_inspect(ic->icmp_type, &enpc);
-               if (!ret || !npf_iscached(&enpc, NPC_ICMP_ID))
+               ret = npfa_icmp4_inspect(ic->icmp_type, &enpc, &hasqid);
+               if (!ret || !hasqid)
                        goto out;
+               enpc.npc_info |= NPC_ICMP_ID;
                break;
        }
        case IPPROTO_ICMPV6: {
                const struct icmp6_hdr *ic6 = enpc.npc_l4.icmp6;
-               ret = npfa_icmp6_inspect(ic6->icmp6_type, &enpc);
-               if (!ret || !npf_iscached(&enpc, NPC_ICMP_ID))
+               ret = npfa_icmp6_inspect(ic6->icmp6_type, &enpc, &hasqid);
+               if (!ret || !hasqid)
                        goto out;
+               enpc.npc_info |= NPC_ICMP_ID;
                break;
        }
        default:
@@ -333,6 +336,15 @@
        if (!npfa_icmp_inspect(npc, &enpc))
                goto err;
 
+       /*
+        * If the ICMP packet had a Query Id, leave now. The packet didn't get
+        * modified, so no need to recache npc.
+        */
+       if (npf_iscached(npc, NPC_ICMP_ID)) {
+               KASSERT(!nbuf_flag_p(nbuf, NBUF_DATAREF_RESET));
+               return false;
+       }
+
        KASSERT(npf_iscached(&enpc, NPC_IP46));
        KASSERT(npf_iscached(&enpc, NPC_LAYER4));
 
diff -r 09641237b2b5 -r 33d02f30f2a5 sys/net/npf/npf_inet.c
--- a/sys/net/npf/npf_inet.c    Thu Mar 22 07:32:07 2018 +0000
+++ b/sys/net/npf/npf_inet.c    Thu Mar 22 08:57:47 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: npf_inet.c,v 1.44 2018/03/21 15:36:28 maxv Exp $       */
+/*     $NetBSD: npf_inet.c,v 1.45 2018/03/22 08:57:47 maxv Exp $       */
 
 /*-
  * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -40,7 +40,7 @@
 
 #ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.44 2018/03/21 15:36:28 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.45 2018/03/22 08:57:47 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -482,6 +482,11 @@
        }
        hlen = npc->npc_hlen;
 
+       /*
+        * Note: we guarantee that the potential "Query Id" field of the
+        * ICMPv4/ICMPv6 packets is in the nbuf. This field is used in the
+        * ICMP ALG.
+        */
        switch (npc->npc_proto) {
        case IPPROTO_TCP:
                /* Cache: layer 4 - TCP. */
@@ -498,13 +503,13 @@
        case IPPROTO_ICMP:
                /* Cache: layer 4 - ICMPv4. */
                npc->npc_l4.icmp = nbuf_advance(nbuf, hlen,
-                   offsetof(struct icmp, icmp_void));
+                   ICMP_MINLEN);
                l4flags = NPC_LAYER4 | NPC_ICMP;
                break;
        case IPPROTO_ICMPV6:
                /* Cache: layer 4 - ICMPv6. */
                npc->npc_l4.icmp6 = nbuf_advance(nbuf, hlen,
-                   offsetof(struct icmp6_hdr, icmp6_data32));
+                   sizeof(struct icmp6_hdr));
                l4flags = NPC_LAYER4 | NPC_ICMP;
                break;
        default:



Home | Main Index | Thread Index | Old Index