From e83f3b316a3a582f31031c9eba0273259a155711 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 22 Aug 2018 00:00:32 -0700 Subject: [PATCH] pimd: Fix pim_mroute_del crash while terminating pimd When pimd is getting terminated, pim_upstream_del() gets called as part of cleaning process. pim_upstream_del() deletes the route and assigns NULL to the up->channel_oil. It also deletes each if_channel by calling the function pim_ifchannel_delete(). pim_ifchannel_delete() internally calls the caller function pim_upstream_del(), if it is the last ifchannel for that upstream. So pim_upstream_del is getting called twice, which will access the up->channel_oil which was already set to NULL before. This results in crash. Fix: pim_ifchannel_delete() should call pim_upstream_del (caller function) only if the up->ref_count > 0. Added an assert(up->ref_count > 0) in the function pim_upstream_del(). Signed-off-by: Sarita Patra --- pimd/pim_ifchannel.c | 11 ++++++++++- pimd/pim_upstream.c | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 92a78c4bb4..3137345037 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -174,7 +174,16 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) ifchannel list is empty before deleting upstream_del ref count will take care of it. */ - pim_upstream_del(pim_ifp->pim, ch->upstream, __PRETTY_FUNCTION__); + if (ch->upstream->ref_count > 0) + pim_upstream_del(pim_ifp->pim, ch->upstream, + __PRETTY_FUNCTION__); + + else + zlog_warn("%s: Avoiding deletion of upstream with ref_count %d " + "from ifchannel(%s): %s", __PRETTY_FUNCTION__, + ch->upstream->ref_count, ch->interface->name, + ch->sg_str); + ch->upstream = NULL; THREAD_OFF(ch->t_ifjoin_expiry_timer); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index db89125a98..15cbf6fbc3 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -167,6 +167,8 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, up->ref_count, up->flags, up->channel_oil->oil_ref_count); + assert(up->ref_count > 0); + --up->ref_count; if (up->ref_count >= 1)