mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	ipvs: move old_secure_tcp into struct netns_ipvs
syzbot reported the following issue :
BUG: KCSAN: data-race in update_defense_level / update_defense_level
read to 0xffffffff861a6260 of 4 bytes by task 3006 on cpu 1:
 update_defense_level+0x621/0xb30 net/netfilter/ipvs/ip_vs_ctl.c:177
 defense_work_handler+0x3d/0xd0 net/netfilter/ipvs/ip_vs_ctl.c:225
 process_one_work+0x3d4/0x890 kernel/workqueue.c:2269
 worker_thread+0xa0/0x800 kernel/workqueue.c:2415
 kthread+0x1d4/0x200 drivers/block/aoe/aoecmd.c:1253
 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:352
write to 0xffffffff861a6260 of 4 bytes by task 7333 on cpu 0:
 update_defense_level+0xa62/0xb30 net/netfilter/ipvs/ip_vs_ctl.c:205
 defense_work_handler+0x3d/0xd0 net/netfilter/ipvs/ip_vs_ctl.c:225
 process_one_work+0x3d4/0x890 kernel/workqueue.c:2269
 worker_thread+0xa0/0x800 kernel/workqueue.c:2415
 kthread+0x1d4/0x200 drivers/block/aoe/aoecmd.c:1253
 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:352
Reported by Kernel Concurrency Sanitizer on:
CPU: 0 PID: 7333 Comm: kworker/0:5 Not tainted 5.4.0-rc3+ #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Workqueue: events defense_work_handler
Indeed, old_secure_tcp is currently a static variable, while it
needs to be a per netns variable.
Fixes: a0840e2e16 ("IPVS: netns, ip_vs_ctl local vars moved to ipvs struct.")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
			
			
This commit is contained in:
		
							parent
							
								
									62931f59ce
								
							
						
					
					
						commit
						c24b75e0f9
					
				
					 2 changed files with 8 additions and 8 deletions
				
			
		| 
						 | 
					@ -889,6 +889,7 @@ struct netns_ipvs {
 | 
				
			||||||
	struct delayed_work	defense_work;   /* Work handler */
 | 
						struct delayed_work	defense_work;   /* Work handler */
 | 
				
			||||||
	int			drop_rate;
 | 
						int			drop_rate;
 | 
				
			||||||
	int			drop_counter;
 | 
						int			drop_counter;
 | 
				
			||||||
 | 
						int			old_secure_tcp;
 | 
				
			||||||
	atomic_t		dropentry;
 | 
						atomic_t		dropentry;
 | 
				
			||||||
	/* locks in ctl.c */
 | 
						/* locks in ctl.c */
 | 
				
			||||||
	spinlock_t		dropentry_lock;  /* drop entry handling */
 | 
						spinlock_t		dropentry_lock;  /* drop entry handling */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -93,7 +93,6 @@ static bool __ip_vs_addr_is_local_v6(struct net *net,
 | 
				
			||||||
static void update_defense_level(struct netns_ipvs *ipvs)
 | 
					static void update_defense_level(struct netns_ipvs *ipvs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sysinfo i;
 | 
						struct sysinfo i;
 | 
				
			||||||
	static int old_secure_tcp = 0;
 | 
					 | 
				
			||||||
	int availmem;
 | 
						int availmem;
 | 
				
			||||||
	int nomem;
 | 
						int nomem;
 | 
				
			||||||
	int to_change = -1;
 | 
						int to_change = -1;
 | 
				
			||||||
| 
						 | 
					@ -174,35 +173,35 @@ static void update_defense_level(struct netns_ipvs *ipvs)
 | 
				
			||||||
	spin_lock(&ipvs->securetcp_lock);
 | 
						spin_lock(&ipvs->securetcp_lock);
 | 
				
			||||||
	switch (ipvs->sysctl_secure_tcp) {
 | 
						switch (ipvs->sysctl_secure_tcp) {
 | 
				
			||||||
	case 0:
 | 
						case 0:
 | 
				
			||||||
		if (old_secure_tcp >= 2)
 | 
							if (ipvs->old_secure_tcp >= 2)
 | 
				
			||||||
			to_change = 0;
 | 
								to_change = 0;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case 1:
 | 
						case 1:
 | 
				
			||||||
		if (nomem) {
 | 
							if (nomem) {
 | 
				
			||||||
			if (old_secure_tcp < 2)
 | 
								if (ipvs->old_secure_tcp < 2)
 | 
				
			||||||
				to_change = 1;
 | 
									to_change = 1;
 | 
				
			||||||
			ipvs->sysctl_secure_tcp = 2;
 | 
								ipvs->sysctl_secure_tcp = 2;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			if (old_secure_tcp >= 2)
 | 
								if (ipvs->old_secure_tcp >= 2)
 | 
				
			||||||
				to_change = 0;
 | 
									to_change = 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case 2:
 | 
						case 2:
 | 
				
			||||||
		if (nomem) {
 | 
							if (nomem) {
 | 
				
			||||||
			if (old_secure_tcp < 2)
 | 
								if (ipvs->old_secure_tcp < 2)
 | 
				
			||||||
				to_change = 1;
 | 
									to_change = 1;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			if (old_secure_tcp >= 2)
 | 
								if (ipvs->old_secure_tcp >= 2)
 | 
				
			||||||
				to_change = 0;
 | 
									to_change = 0;
 | 
				
			||||||
			ipvs->sysctl_secure_tcp = 1;
 | 
								ipvs->sysctl_secure_tcp = 1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case 3:
 | 
						case 3:
 | 
				
			||||||
		if (old_secure_tcp < 2)
 | 
							if (ipvs->old_secure_tcp < 2)
 | 
				
			||||||
			to_change = 1;
 | 
								to_change = 1;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	old_secure_tcp = ipvs->sysctl_secure_tcp;
 | 
						ipvs->old_secure_tcp = ipvs->sysctl_secure_tcp;
 | 
				
			||||||
	if (to_change >= 0)
 | 
						if (to_change >= 0)
 | 
				
			||||||
		ip_vs_protocol_timeout_change(ipvs,
 | 
							ip_vs_protocol_timeout_change(ipvs,
 | 
				
			||||||
					      ipvs->sysctl_secure_tcp > 1);
 | 
										      ipvs->sysctl_secure_tcp > 1);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue