From 24416c29172a97bf59eabfb3b32fd8cf763102c8 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Thu, 9 Jan 2020 19:24:46 -0700 Subject: [PATCH] netfilter: Unlock xt_table later This ensures that two concurrent writers through iptables-restore cannot overwrite each other. Fixes the following- <6> Unable to handle kernel paging request at virtual address 006b6b6b6b6b6bc5 <6> [006b6b6b6b6b6bc5] address between user and kernel address ranges <2> pc : ipt_do_table+0x3b8/0x660 <2> lr : ipt_do_table+0x31c/0x660 <2> Call trace: <2> ipt_do_table+0x3b8/0x660 <2> iptable_mangle_hook+0x58/0xf8 <2> nf_hook_slow+0x48/0xd8 <2> __ip_local_out+0xf4/0x138 <2> __ip_queue_xmit+0x348/0x3a0 <2> ip_queue_xmit+0x10/0x18 <2> __tcp_transmit_skb+0x734/0xaa8 <2> __tcp_retransmit_skb+0x5b8/0x930 <2> tcp_send_loss_probe+0x19c/0x300 <2> tcp_write_timer_handler+0x14c/0x238 <2> tcp_write_timer+0x74/0xa0 <2> call_timer_fn+0xc0/0x1c0 <2> run_timer_softirq+0x2f8/0xa30 <2> __do_softirq+0x1dc/0x384 This enforces the cleanup of the old entries under the xt_table lock. CRs-fixed: 2612021 Change-Id: If721ceb7891e58847eae5c1ad9c5e9aea4c569e3 Signed-off-by: Subash Abhinov Kasiviswanathan --- net/ipv4/netfilter/arp_tables.c | 3 +-- net/ipv4/netfilter/ip_tables.c | 3 +-- net/ipv6/netfilter/ip6_tables.c | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index f1f78a742b36..85cb18911278 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -921,8 +921,6 @@ static int __do_replace(struct net *net, const char *name, (newinfo->number <= oldinfo->initial_entries)) module_put(t->me); - xt_table_unlock(t); - get_old_counters(oldinfo, counters); /* Decrease module usage counts and free resource */ @@ -937,6 +935,7 @@ static int __do_replace(struct net *net, const char *name, net_warn_ratelimited("arptables: counters copy to user failed while replacing table\n"); } vfree(counters); + xt_table_unlock(t); return ret; put_module: diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 10b91ebdf213..9f98bc5c3ba4 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1076,8 +1076,6 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, (newinfo->number <= oldinfo->initial_entries)) module_put(t->me); - xt_table_unlock(t); - get_old_counters(oldinfo, counters); /* Decrease module usage counts and free resource */ @@ -1091,6 +1089,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, net_warn_ratelimited("iptables: counters copy to user failed while replacing table\n"); } vfree(counters); + xt_table_unlock(t); return ret; put_module: diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index c973ace208c5..f2637bfb9198 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1093,8 +1093,6 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, (newinfo->number <= oldinfo->initial_entries)) module_put(t->me); - xt_table_unlock(t); - get_old_counters(oldinfo, counters); /* Decrease module usage counts and free resource */ @@ -1108,6 +1106,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, net_warn_ratelimited("ip6tables: counters copy to user failed while replacing table\n"); } vfree(counters); + xt_table_unlock(t); return ret; put_module: