]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: use list to mark for removal when scoring
authorStephen Worley <sworley@cumulusnetworks.com>
Tue, 1 Sep 2020 18:53:09 +0000 (14:53 -0400)
committerStephen Worley <sworley@cumulusnetworks.com>
Mon, 28 Sep 2020 16:41:00 +0000 (12:41 -0400)
In scoring our NHEs during shutdown there is a chance we could release mutliple
NHEs at the same time during one iteration. This can cause memory corruption
if the two being released are directly next to each other in the hash table.

hash_iterate accounts for releasing one during the iteration but not
two by setting hbnext before release but if hbnext is also freed,
we obviously can have a problem.

Signed-off-by: Stephen Worley <sworley@cumulusnetworks.com>
zebra/zebra_nhg.c

index cfc5a4f323f61f2c7dcdf5265a77fa4cf5aec39a..ac8f4745d65e1c023245ae4a43d70478af37a80f 100644 (file)
@@ -2893,7 +2893,7 @@ struct nhg_hash_entry *zebra_nhg_proto_del(uint32_t id)
 
 struct nhg_score_proto_iter {
        int type;
-       unsigned long found;
+       struct list *found;
 };
 
 static void zebra_nhg_score_proto_entry(struct hash_bucket *bucket, void *arg)
@@ -2906,27 +2906,42 @@ static void zebra_nhg_score_proto_entry(struct hash_bucket *bucket, void *arg)
 
        /* Needs to match type and outside zebra ID space */
        if (nhe->type == iter->type && nhe->id >= ZEBRA_NHG_PROTO_LOWER) {
-               iter->found++;
-
                if (IS_ZEBRA_DEBUG_NHG_DETAIL)
                        zlog_debug(
                                "%s: found nhe %p (%u), vrf %d, type %s after client disconnect",
                                __func__, nhe, nhe->id, nhe->vrf_id,
                                zebra_route_string(nhe->type));
 
-               /* This should be the last ref if we remove client routes too */
-               zebra_nhg_decrement_ref(nhe);
+               /* Add to removal list */
+               listnode_add(iter->found, nhe);
        }
 }
 
 /* Remove specific by proto NHGs */
 unsigned long zebra_nhg_score_proto(int type)
 {
+       struct nhg_hash_entry *nhe;
        struct nhg_score_proto_iter iter = {};
+       struct listnode *ln;
+       unsigned long count;
 
        iter.type = type;
+       iter.found = list_new();
 
+       /* Find matching entries to remove */
        hash_iterate(zrouter.nhgs_id, zebra_nhg_score_proto_entry, &iter);
 
-       return iter.found;
+       /* Now remove them */
+       for (ALL_LIST_ELEMENTS_RO(iter.found, ln, nhe)) {
+               /*
+                * This should be the last ref if we remove client routes too,
+                * and thus should remove and free them.
+                */
+               zebra_nhg_decrement_ref(nhe);
+       }
+
+       count = iter.found->count;
+       list_delete(&iter.found);
+
+       return count;
 }