summaryrefslogtreecommitdiffstats
path: root/prevent-runtime-conntrack-changes.patch
diff options
context:
space:
mode:
Diffstat (limited to 'prevent-runtime-conntrack-changes.patch')
-rw-r--r--prevent-runtime-conntrack-changes.patch74
1 files changed, 74 insertions, 0 deletions
diff --git a/prevent-runtime-conntrack-changes.patch b/prevent-runtime-conntrack-changes.patch
new file mode 100644
index 000000000..59d62f3de
--- /dev/null
+++ b/prevent-runtime-conntrack-changes.patch
@@ -0,0 +1,74 @@
+Jon Masters correctly points out that conntrack hash sizes
+(nf_conntrack_htable_size) are global (not per-netns) and
+modifiable at runtime via /sys/module/nf_conntrack/hashsize .
+
+Steps to reproduce:
+ clone(CLONE_NEWNET)
+ [grow /sys/module/nf_conntrack/hashsize]
+ exit()
+
+At netns exit we are going to scan random memory for conntracks to be killed.
+
+Apparently there is a code which deals with hashtable resize for
+init_net (and it was there befode netns conntrack code), so prohibit
+hashsize modification if there is more than one netns exists.
+
+To change hashtable sizes, you need to reload module.
+
+Expectation hashtable size was simply glued to a variable with no code
+to rehash expectations, so it was a bug to allow writing to it.
+Make "expect_hashsize" readonly.
+
+This is temporarily until we figure out what to do.
+
+Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
+Cc: stable@kernel.org
+---
+
+ net/netfilter/nf_conntrack_core.c | 15 +++++++++++++++
+ net/netfilter/nf_conntrack_expect.c | 2 +-
+ 2 files changed, 16 insertions(+), 1 deletion(-)
+
+--- a/net/netfilter/nf_conntrack_core.c
++++ b/net/netfilter/nf_conntrack_core.c
+@@ -21,6 +21,7 @@
+ #include <linux/stddef.h>
+ #include <linux/slab.h>
+ #include <linux/random.h>
++#include <linux/rtnetlink.h>
+ #include <linux/jhash.h>
+ #include <linux/err.h>
+ #include <linux/percpu.h>
+@@ -1198,6 +1199,20 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
+ if (!nf_conntrack_htable_size)
+ return param_set_uint(val, kp);
+
++ {
++ struct net *net;
++ unsigned int nr;
++
++ nr = 0;
++ rtnl_lock();
++ for_each_net(net)
++ nr++;
++ rtnl_unlock();
++ /* init_net always exists */
++ if (nr != 1)
++ return -EINVAL;
++ }
++
+ hashsize = simple_strtoul(val, NULL, 0);
+ if (!hashsize)
+ return -EINVAL;
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -569,7 +569,7 @@ static void exp_proc_remove(struct net *net)
+ #endif /* CONFIG_PROC_FS */
+ }
+
+-module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0600);
++module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0400);
+
+ int nf_conntrack_expect_init(struct net *net)
+ {
+