]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: clean up attribute parsing state before ret
authorQuentin Young <qlyoung@cumulusnetworks.com>
Tue, 26 Nov 2019 19:42:40 +0000 (14:42 -0500)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Thu, 16 Jan 2020 19:36:52 +0000 (14:36 -0500)
Early exits without appropriate cleanup were causing obscure double
frees and other issues later on in the attribute parsing code. If we
return anything except a hard attribute parse error, we have cleanup and
refcounts to manage.

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
bgpd/bgp_attr.c

index d6260a0806a2f6b4c92a19a27a4c87c86befe3bb..ec63a7178c2958986001b0fdd64a515437f2901c 100644 (file)
@@ -2476,7 +2476,8 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
 
                        bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
                                        BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
-                       return BGP_ATTR_PARSE_ERROR;
+                       ret = BGP_ATTR_PARSE_ERROR;
+                       goto done;
                }
 
                /* Fetch attribute flag and type. */
@@ -2499,7 +2500,8 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
 
                        bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
                                        BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
-                       return BGP_ATTR_PARSE_ERROR;
+                       ret = BGP_ATTR_PARSE_ERROR;
+                       goto done;
                }
 
                /* Check extended attribue length bit. */
@@ -2520,7 +2522,8 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
 
                        bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
                                        BGP_NOTIFY_UPDATE_MAL_ATTR);
-                       return BGP_ATTR_PARSE_ERROR;
+                       ret = BGP_ATTR_PARSE_ERROR;
+                       goto done;
                }
 
                /* Set type to bitmap to check duplicate attribute.  `type' is
@@ -2577,7 +2580,8 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
                                BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, ndata,
                                ndl + lfl + 1);
 
-                       return BGP_ATTR_PARSE_ERROR;
+                       ret = BGP_ATTR_PARSE_ERROR;
+                       goto done;
                }
 
                struct bgp_attr_parser_args attr_args = {
@@ -2602,7 +2606,7 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
                                attr_args.total);
                        if (ret == BGP_ATTR_PARSE_PROCEED)
                                continue;
-                       return ret;
+                       goto done;
                }
 
                /* OK check attribute and store it's value. */
@@ -2680,32 +2684,25 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
                        bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
                                        BGP_NOTIFY_UPDATE_MAL_ATTR);
                        ret = BGP_ATTR_PARSE_ERROR;
+                       goto done;
                }
 
                if (ret == BGP_ATTR_PARSE_EOR) {
-                       if (as4_path)
-                               aspath_unintern(&as4_path);
-                       return ret;
+                       goto done;
                }
 
-               /* If hard error occurred immediately return to the caller. */
                if (ret == BGP_ATTR_PARSE_ERROR) {
                        flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR,
                                  "%s: Attribute %s, parse error", peer->host,
                                  lookup_msg(attr_str, type, NULL));
-                       if (as4_path)
-                               aspath_unintern(&as4_path);
-                       return ret;
+                       goto done;
                }
                if (ret == BGP_ATTR_PARSE_WITHDRAW) {
-
                        flog_warn(
                                EC_BGP_ATTRIBUTE_PARSE_WITHDRAW,
                                "%s: Attribute %s, parse error - treating as withdrawal",
                                peer->host, lookup_msg(attr_str, type, NULL));
-                       if (as4_path)
-                               aspath_unintern(&as4_path);
-                       return ret;
+                       goto done;
                }
 
                /* Check the fetched length. */
@@ -2715,9 +2712,8 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
                                  peer->host, lookup_msg(attr_str, type, NULL));
                        bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
                                        BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
-                       if (as4_path)
-                               aspath_unintern(&as4_path);
-                       return BGP_ATTR_PARSE_ERROR;
+                       ret = BGP_ATTR_PARSE_ERROR;
+                       goto done;
                }
        }
 
@@ -2728,9 +2724,9 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
                          lookup_msg(attr_str, type, NULL));
                bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
                                BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
-               if (as4_path)
-                       aspath_unintern(&as4_path);
-               return BGP_ATTR_PARSE_ERROR;
+
+               ret = BGP_ATTR_PARSE_ERROR;
+               goto done;
        }
 
        /*
@@ -2749,16 +2745,14 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
        if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))
            && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI))) {
                if (bgp_attr_nexthop_valid(peer, attr) < 0) {
-                       return BGP_ATTR_PARSE_ERROR;
+                       ret = BGP_ATTR_PARSE_ERROR;
+                       goto done;
                }
        }
 
        /* Check all mandatory well-known attributes are present */
-       if ((ret = bgp_attr_check(peer, attr)) < 0) {
-               if (as4_path)
-                       aspath_unintern(&as4_path);
-               return ret;
-       }
+       if ((ret = bgp_attr_check(peer, attr)) < 0)
+               goto done;
 
        /*
         * At this place we can see whether we got AS4_PATH and/or
@@ -2781,22 +2775,10 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
                                        &as4_aggregator_addr)) {
                bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
                                BGP_NOTIFY_UPDATE_MAL_ATTR);
-               if (as4_path)
-                       aspath_unintern(&as4_path);
-               return BGP_ATTR_PARSE_ERROR;
+               ret = BGP_ATTR_PARSE_ERROR;
+               goto done;
        }
 
-       /* At this stage, we have done all fiddling with as4, and the
-        * resulting info is in attr->aggregator resp. attr->aspath
-        * so we can chuck as4_aggregator and as4_path alltogether in
-        * order to save memory
-        */
-       if (as4_path) {
-               aspath_unintern(&as4_path); /* unintern - it is in the hash */
-               /* The flag that we got this is still there, but that does not
-                * do any trouble
-                */
-       }
        /*
         * The "rest" of the code does nothing with as4_aggregator.
         * there is no memory attached specifically which is not part
@@ -2810,21 +2792,42 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
        if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) {
                ret = bgp_attr_aspath_check(peer, attr);
                if (ret != BGP_ATTR_PARSE_PROCEED)
-                       return ret;
+                       goto done;
        }
-       /* Finally intern unknown attribute. */
-       if (attr->transit)
-               attr->transit = transit_intern(attr->transit);
-       if (attr->encap_subtlvs)
-               attr->encap_subtlvs =
-                       encap_intern(attr->encap_subtlvs, ENCAP_SUBTLV_TYPE);
 #if ENABLE_BGP_VNC
        if (attr->vnc_subtlvs)
                attr->vnc_subtlvs =
                        encap_intern(attr->vnc_subtlvs, VNC_SUBTLV_TYPE);
 #endif
 
-       return BGP_ATTR_PARSE_PROCEED;
+       ret = BGP_ATTR_PARSE_PROCEED;
+
+done:
+       /*
+        * At this stage, we have done all fiddling with as4, and the
+        * resulting info is in attr->aggregator resp. attr->aspath so
+        * we can chuck as4_aggregator and as4_path alltogether in order
+        * to save memory
+        */
+       if (as4_path) {
+               /*
+                * unintern - it is in the hash
+                * The flag that we got this is still there, but that
+                * does not do any trouble
+                */
+               aspath_unintern(&as4_path);
+       }
+
+       if (ret != BGP_ATTR_PARSE_ERROR) {
+               /* Finally intern unknown attribute. */
+               if (attr->transit)
+                       attr->transit = transit_intern(attr->transit);
+               if (attr->encap_subtlvs)
+                       attr->encap_subtlvs = encap_intern(attr->encap_subtlvs,
+                                                          ENCAP_SUBTLV_TYPE);
+       }
+
+       return ret;
 }
 
 /*