diff options
| author | Eric Dumazet <edumazet@google.com> | 2019-10-23 12:53:03 -0400 |
|---|---|---|
| committer | Simon Horman <horms@verge.net.au> | 2019-10-24 05:56:02 -0400 |
| commit | c24b75e0f9239e78105f81c5f03a751641eb07ef (patch) | |
| tree | 25b22e73798a8b701d8ccd56ed61de5ba4b38f32 | |
| parent | 62931f59ce9cbabb934a431f48f2f1f441c605ac (diff) | |
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: a0840e2e165a ("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>
| -rw-r--r-- | include/net/ip_vs.h | 1 | ||||
| -rw-r--r-- | net/netfilter/ipvs/ip_vs_ctl.c | 15 |
2 files changed, 8 insertions, 8 deletions
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 3759167f91f5..078887c8c586 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h | |||
| @@ -889,6 +889,7 @@ struct netns_ipvs { | |||
| 889 | struct delayed_work defense_work; /* Work handler */ | 889 | struct delayed_work defense_work; /* Work handler */ |
| 890 | int drop_rate; | 890 | int drop_rate; |
| 891 | int drop_counter; | 891 | int drop_counter; |
| 892 | int old_secure_tcp; | ||
| 892 | atomic_t dropentry; | 893 | atomic_t dropentry; |
| 893 | /* locks in ctl.c */ | 894 | /* locks in ctl.c */ |
| 894 | spinlock_t dropentry_lock; /* drop entry handling */ | 895 | spinlock_t dropentry_lock; /* drop entry handling */ |
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index c8f81dd15c83..3cccc88ef817 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c | |||
| @@ -93,7 +93,6 @@ static bool __ip_vs_addr_is_local_v6(struct net *net, | |||
| 93 | static void update_defense_level(struct netns_ipvs *ipvs) | 93 | static void update_defense_level(struct netns_ipvs *ipvs) |
| 94 | { | 94 | { |
| 95 | struct sysinfo i; | 95 | struct sysinfo i; |
| 96 | static int old_secure_tcp = 0; | ||
| 97 | int availmem; | 96 | int availmem; |
| 98 | int nomem; | 97 | int nomem; |
| 99 | int to_change = -1; | 98 | int to_change = -1; |
| @@ -174,35 +173,35 @@ static void update_defense_level(struct netns_ipvs *ipvs) | |||
| 174 | spin_lock(&ipvs->securetcp_lock); | 173 | spin_lock(&ipvs->securetcp_lock); |
| 175 | switch (ipvs->sysctl_secure_tcp) { | 174 | switch (ipvs->sysctl_secure_tcp) { |
| 176 | case 0: | 175 | case 0: |
| 177 | if (old_secure_tcp >= 2) | 176 | if (ipvs->old_secure_tcp >= 2) |
| 178 | to_change = 0; | 177 | to_change = 0; |
| 179 | break; | 178 | break; |
| 180 | case 1: | 179 | case 1: |
| 181 | if (nomem) { | 180 | if (nomem) { |
| 182 | if (old_secure_tcp < 2) | 181 | if (ipvs->old_secure_tcp < 2) |
| 183 | to_change = 1; | 182 | to_change = 1; |
| 184 | ipvs->sysctl_secure_tcp = 2; | 183 | ipvs->sysctl_secure_tcp = 2; |
| 185 | } else { | 184 | } else { |
| 186 | if (old_secure_tcp >= 2) | 185 | if (ipvs->old_secure_tcp >= 2) |
| 187 | to_change = 0; | 186 | to_change = 0; |
| 188 | } | 187 | } |
| 189 | break; | 188 | break; |
| 190 | case 2: | 189 | case 2: |
| 191 | if (nomem) { | 190 | if (nomem) { |
| 192 | if (old_secure_tcp < 2) | 191 | if (ipvs->old_secure_tcp < 2) |
| 193 | to_change = 1; | 192 | to_change = 1; |
| 194 | } else { | 193 | } else { |
| 195 | if (old_secure_tcp >= 2) | 194 | if (ipvs->old_secure_tcp >= 2) |
| 196 | to_change = 0; | 195 | to_change = 0; |
| 197 | ipvs->sysctl_secure_tcp = 1; | 196 | ipvs->sysctl_secure_tcp = 1; |
| 198 | } | 197 | } |
| 199 | break; | 198 | break; |
| 200 | case 3: | 199 | case 3: |
| 201 | if (old_secure_tcp < 2) | 200 | if (ipvs->old_secure_tcp < 2) |
| 202 | to_change = 1; | 201 | to_change = 1; |
| 203 | break; | 202 | break; |
| 204 | } | 203 | } |
| 205 | old_secure_tcp = ipvs->sysctl_secure_tcp; | 204 | ipvs->old_secure_tcp = ipvs->sysctl_secure_tcp; |
| 206 | if (to_change >= 0) | 205 | if (to_change >= 0) |
| 207 | ip_vs_protocol_timeout_change(ipvs, | 206 | ip_vs_protocol_timeout_change(ipvs, |
| 208 | ipvs->sysctl_secure_tcp > 1); | 207 | ipvs->sysctl_secure_tcp > 1); |
