pimd: fix crash due to double free#21354
Conversation
local_membership_del may delete the ifchannel and last upstream, which runs pim_channel_oil_upstream_deref() and frees the channel_oil. IGMP still holds *oilp in that case; a second pim_channel_oil_del() corrupts the RB tree (typed_rb_remove on freed / zeroed links). Signed-off-by: Jafar Al-Gharaibeh <jafar@atcorp.com>
|
@Mergifyio backport stable/10.6 stable/10.5 stable/10.4 |
✅ Backports have been createdDetails
|
Greptile SummaryThis PR fixes a double-free crash in Changes:
The fix correctly uses the RB tree as the source of truth for object liveness rather than touching freed memory, which is the right approach for this data structure. Confidence Score: 5/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant IGMP
participant tib_sg_gm_prune
participant pim_channel_del_oif
participant pim_ifchannel_local_membership_del
participant pim_channel_oil_upstream_deref
participant pim_channel_oil_del
participant RB_Tree as RB Tree
IGMP->>tib_sg_gm_prune: prune(pim, sg, oif, &oilp)
Note over tib_sg_gm_prune: Guard: if (!*oilp) return (NEW)
tib_sg_gm_prune->>pim_channel_del_oif: del_oif(*oilp, oif, PROTO_GM)
tib_sg_gm_prune->>pim_ifchannel_local_membership_del: del(oif, &sg)
pim_ifchannel_local_membership_del->>pim_channel_oil_upstream_deref: deref(c_oil) [last upstream]
pim_channel_oil_upstream_deref->>pim_channel_oil_del: del(c_oil) [refcount → 0]
pim_channel_oil_del->>RB_Tree: rb_pim_oil_del (removes entry)
pim_channel_oil_del-->>pim_channel_oil_upstream_deref: freed, returns NULL
Note over tib_sg_gm_prune: BUG (OLD): pim_channel_oil_del(*oilp) → double-free!
Note over tib_sg_gm_prune: FIX (NEW): pim_find_channel_oil(pim, &sg)
tib_sg_gm_prune->>RB_Tree: find_channel_oil(pim, &sg) → live
alt live == *oilp (oil still alive)
tib_sg_gm_prune->>pim_channel_oil_del: del(live) — safe
pim_channel_oil_del-->>tib_sg_gm_prune: NULL or c_oil
tib_sg_gm_prune-->>IGMP: *oilp = result
else live != *oilp (already freed by upstream_deref)
tib_sg_gm_prune-->>IGMP: *oilp = NULL (no double-free)
end
Reviews (1): Last reviewed commit: "pimd: fix crash due to double free" | Re-trigger Greptile |
pimd: fix crash due to double free (backport #21354)
pimd: fix crash due to double free (backport #21354)
pimd: fix crash due to double free (backport #21354)
local_membership_del may delete the ifchannel and last upstream, which runs pim_channel_oil_upstream_deref() and frees the channel_oil. IGMP still holds *oilp in that case; a second pim_channel_oil_del() corrupts the RB tree (typed_rb_remove on freed / zeroed links).