From 8f830b8c64622099d4a6d3cc12dbc2f8009b45e2 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 1 Sep 2020 14:53:09 -0400 Subject: [PATCH] zebra: use list to mark for removal when scoring 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 --- zebra/zebra_nhg.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index cfc5a4f323..ac8f4745d6 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -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; } -- 2.39.5