75 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			75 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| 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)
 | |
|  {
 | |
| 
 |