Skip to content

Commit 50d84ed

Browse files
committed
ipmr: add debug check for mr table cleanup
jira LE-2522 Rebuild_History Non-Buildable kernel-5.14.0-503.29.1.el9_5 commit-author Paolo Abeni <[email protected]> commit 11b6e70 The multicast route tables lifecycle, for both ipv4 and ipv6, is protected by RCU using the RTNL lock for write access. In many places a table pointer escapes the RCU (or RTNL) protected critical section, but such scenarios are actually safe because tables are deleted only at namespace cleanup time or just after allocation, in case of default rule creation failure. Tables freed at namespace cleanup time are assured to be alive for the whole netns lifetime; tables freed just after creation time are never exposed to other possible users. Ensure that the free conditions are respected in ip{,6}mr_free_table, to document the locking schema and to prevent future possible introduction of 'table del' operation from breaking it. Reviewed-by: David Ahern <[email protected]> Signed-off-by: Paolo Abeni <[email protected]> (cherry picked from commit 11b6e70) Signed-off-by: Jonathan Maple <[email protected]>
1 parent 7399596 commit 50d84ed

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

net/ipv4/ipmr.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ static void ipmr_expire_process(struct timer_list *t);
114114
lockdep_rtnl_is_held() || \
115115
list_empty(&net->ipv4.mr_tables))
116116

117+
static bool ipmr_can_free_table(struct net *net)
118+
{
119+
return !check_net(net) || !net->ipv4.mr_rules_ops;
120+
}
121+
117122
static struct mr_table *ipmr_mr_table_iter(struct net *net,
118123
struct mr_table *mrt)
119124
{
@@ -301,6 +306,11 @@ EXPORT_SYMBOL(ipmr_rule_default);
301306
#define ipmr_for_each_table(mrt, net) \
302307
for (mrt = net->ipv4.mrt; mrt; mrt = NULL)
303308

309+
static bool ipmr_can_free_table(struct net *net)
310+
{
311+
return !check_net(net);
312+
}
313+
304314
static struct mr_table *ipmr_mr_table_iter(struct net *net,
305315
struct mr_table *mrt)
306316
{
@@ -412,6 +422,10 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
412422

413423
static void ipmr_free_table(struct mr_table *mrt)
414424
{
425+
struct net *net = read_pnet(&mrt->net);
426+
427+
DEBUG_NET_WARN_ON_ONCE(!ipmr_can_free_table(net));
428+
415429
timer_shutdown_sync(&mrt->ipmr_expire_timer);
416430
mroute_clean_tables(mrt, MRT_FLUSH_VIFS | MRT_FLUSH_VIFS_STATIC |
417431
MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC);

net/ipv6/ip6mr.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ static void ipmr_expire_process(struct timer_list *t);
101101
lockdep_rtnl_is_held() || \
102102
list_empty(&net->ipv6.mr6_tables))
103103

104+
static bool ip6mr_can_free_table(struct net *net)
105+
{
106+
return !check_net(net) || !net->ipv6.mr6_rules_ops;
107+
}
108+
104109
static struct mr_table *ip6mr_mr_table_iter(struct net *net,
105110
struct mr_table *mrt)
106111
{
@@ -289,6 +294,11 @@ EXPORT_SYMBOL(ip6mr_rule_default);
289294
#define ip6mr_for_each_table(mrt, net) \
290295
for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
291296

297+
static bool ip6mr_can_free_table(struct net *net)
298+
{
299+
return !check_net(net);
300+
}
301+
292302
static struct mr_table *ip6mr_mr_table_iter(struct net *net,
293303
struct mr_table *mrt)
294304
{
@@ -390,6 +400,10 @@ static struct mr_table *ip6mr_new_table(struct net *net, u32 id)
390400

391401
static void ip6mr_free_table(struct mr_table *mrt)
392402
{
403+
struct net *net = read_pnet(&mrt->net);
404+
405+
DEBUG_NET_WARN_ON_ONCE(!ip6mr_can_free_table(net));
406+
393407
timer_shutdown_sync(&mrt->ipmr_expire_timer);
394408
mroute_clean_tables(mrt, MRT6_FLUSH_MIFS | MRT6_FLUSH_MIFS_STATIC |
395409
MRT6_FLUSH_MFC | MRT6_FLUSH_MFC_STATIC);

0 commit comments

Comments
 (0)