]> git.ipfire.org Git - thirdparty/kernel/linux.git/commit
ipmr: Free mr_table after RCU grace period.
authorKuniyuki Iwashima <kuniyu@google.com>
Thu, 23 Apr 2026 05:34:54 +0000 (05:34 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 28 Apr 2026 01:46:17 +0000 (18:46 -0700)
commitb3b6babf47517fde6b6de2493dea28e8831b9347
treec9c03ebda71a37f0c745b87ab7350e41e5a2c918
parent5b0c911bcdbd982f7748d11c0b39ec5808eae2de
ipmr: Free mr_table after RCU grace period.

With CONFIG_IP_MROUTE_MULTIPLE_TABLES=n, ipmr_fib_lookup()
does not check if net->ipv4.mrt is NULL.

Since default_device_exit_batch() is called after ->exit_rtnl(),
a device could receive IGMP packets and access net->ipv4.mrt
during/after ipmr_rules_exit_rtnl().

If ipmr_rules_exit_rtnl() had already cleared it and freed the
memory, the access would trigger null-ptr-deref or use-after-free.

Let's fix it by using RCU helper and free mrt after RCU grace
period.

In addition, check_net(net) is added to mroute_clean_tables()
and ipmr_cache_unresolved() to synchronise via mfc_unres_lock.
This prevents ipmr_cache_unresolved() from putting skb into
c->_c.mfc_un.unres.unresolved after mroute_clean_tables()
purges it.

For the same reason, timer_shutdown_sync() is moved after
mroute_clean_tables().

Since rhltable_destroy() holds mutex internally, rcu_work is
used, and it is placed as the first member because rcu_head
must be placed within <4K offset.  mr_table is alraedy 3864
bytes without rcu_work.

Note that IP6MR is not yet converted to ->exit_rtnl(), so this
change is not needed for now but will be.

Fixes: b22b01867406 ("ipmr: Convert ipmr_net_exit_batch() to ->exit_rtnl().")
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260423053456.4097409-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/linux/mroute_base.h
net/ipv4/ipmr.c
net/ipv4/ipmr_base.c