diff options
-rw-r--r-- | kernel.spec | 9 | ||||
-rw-r--r-- | netfilter-nf_nat-fix-oops-on-netns-removal.patch | 98 |
2 files changed, 107 insertions, 0 deletions
diff --git a/kernel.spec b/kernel.spec index 09674a11e..b64eb4e24 100644 --- a/kernel.spec +++ b/kernel.spec @@ -752,6 +752,9 @@ Patch25109: revert-input-wacom-testing-result-shows-get_report-is-unnecessary.pa #rhbz 1021036, submitted upstream Patch25110: 0001-ideapad-laptop-Change-Lenovo-Yoga-2-series-rfkill-ha.patch +#rhbz 1015989 +Patch25111: netfilter-nf_nat-fix-oops-on-netns-removal.patch + # END OF PATCH DEFINITIONS %endif @@ -1472,6 +1475,9 @@ ApplyPatch revert-input-wacom-testing-result-shows-get_report-is-unnecessary.pat #rhbz 1021036, submitted upstream ApplyPatch 0001-ideapad-laptop-Change-Lenovo-Yoga-2-series-rfkill-ha.patch +#rhbz 1015989 +ApplyPatch netfilter-nf_nat-fix-oops-on-netns-removal.patch + # END OF PATCH APPLICATIONS %endif @@ -2284,6 +2290,9 @@ fi # ||----w | # || || %changelog +* Mon Jun 30 2014 Josh Boyer <jwboyer@fedoraproject.org> +- Backport netfilter panic fix (rhbz 1015989) + * Sun Jun 29 2014 Peter Robinson <pbrobinson@fedoraproject.org> - Rebase ARM based BeagleBone and Utilite stable patches diff --git a/netfilter-nf_nat-fix-oops-on-netns-removal.patch b/netfilter-nf_nat-fix-oops-on-netns-removal.patch new file mode 100644 index 000000000..4cd521895 --- /dev/null +++ b/netfilter-nf_nat-fix-oops-on-netns-removal.patch @@ -0,0 +1,98 @@ +Bugzilla: 1015989 +Upstream-status: 3.16-rc3 and queued for stable + +From 945b2b2d259d1a4364a2799e80e8ff32f8c6ee6f Mon Sep 17 00:00:00 2001 +From: Florian Westphal <fw@strlen.de> +Date: Sat, 7 Jun 2014 21:17:04 +0200 +Subject: [PATCH] netfilter: nf_nat: fix oops on netns removal + +Quoting Samu Kallio: + + Basically what's happening is, during netns cleanup, + nf_nat_net_exit gets called before ipv4_net_exit. As I understand + it, nf_nat_net_exit is supposed to kill any conntrack entries which + have NAT context (through nf_ct_iterate_cleanup), but for some + reason this doesn't happen (perhaps something else is still holding + refs to those entries?). + + When ipv4_net_exit is called, conntrack entries (including those + with NAT context) are cleaned up, but the + nat_bysource hashtable is long gone - freed in nf_nat_net_exit. The + bug happens when attempting to free a conntrack entry whose NAT hash + 'prev' field points to a slot in the freed hash table (head for that + bin). + +We ignore conntracks with null nat bindings. But this is wrong, +as these are in bysource hash table as well. + +Restore nat-cleaning for the netns-is-being-removed case. + +bug: +https://bugzilla.kernel.org/show_bug.cgi?id=65191 + +Fixes: c2d421e1718 ('netfilter: nf_nat: fix race when unloading protocol modules') +Reported-by: Samu Kallio <samu.kallio@aberdeencloud.com> +Debugged-by: Samu Kallio <samu.kallio@aberdeencloud.com> +Signed-off-by: Florian Westphal <fw@strlen.de> +Tested-by: Samu Kallio <samu.kallio@aberdeencloud.com> +Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> +--- + net/netfilter/nf_nat_core.c | 35 ++++++++++++++++++++++++++++++++++- + 1 file changed, 34 insertions(+), 1 deletion(-) + +diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c +index 09096a670c45..a49907b1dabc 100644 +--- a/net/netfilter/nf_nat_core.c ++++ b/net/netfilter/nf_nat_core.c +@@ -525,6 +525,39 @@ static int nf_nat_proto_remove(struct nf_conn *i, void *data) + return i->status & IPS_NAT_MASK ? 1 : 0; + } + ++static int nf_nat_proto_clean(struct nf_conn *ct, void *data) ++{ ++ struct nf_conn_nat *nat = nfct_nat(ct); ++ ++ if (nf_nat_proto_remove(ct, data)) ++ return 1; ++ ++ if (!nat || !nat->ct) ++ return 0; ++ ++ /* This netns is being destroyed, and conntrack has nat null binding. ++ * Remove it from bysource hash, as the table will be freed soon. ++ * ++ * Else, when the conntrack is destoyed, nf_nat_cleanup_conntrack() ++ * will delete entry from already-freed table. ++ */ ++ if (!del_timer(&ct->timeout)) ++ return 1; ++ ++ spin_lock_bh(&nf_nat_lock); ++ hlist_del_rcu(&nat->bysource); ++ ct->status &= ~IPS_NAT_DONE_MASK; ++ nat->ct = NULL; ++ spin_unlock_bh(&nf_nat_lock); ++ ++ add_timer(&ct->timeout); ++ ++ /* don't delete conntrack. Although that would make things a lot ++ * simpler, we'd end up flushing all conntracks on nat rmmod. ++ */ ++ return 0; ++} ++ + static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto) + { + struct nf_nat_proto_clean clean = { +@@ -795,7 +828,7 @@ static void __net_exit nf_nat_net_exit(struct net *net) + { + struct nf_nat_proto_clean clean = {}; + +- nf_ct_iterate_cleanup(net, &nf_nat_proto_remove, &clean, 0, 0); ++ nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean, 0, 0); + synchronize_rcu(); + nf_ct_free_hashtable(net->ct.nat_bysource, net->ct.nat_htable_size); + } +-- +1.9.3 + |