Skip to content

Commit f2da9a9

Browse files
Julian Anastasovummakynes
authored andcommitted
ipvs: fix races around the conn_lfactor and svc_lfactor sysctl vars
Sashiko warns that the new sysctls vars can be changed after the hash tables are destroyed and their respective resizing works canceled, leading to mod_delayed_work() being called for canceled works. Solve this in different ways. conn_tab can be present even without services and is destroyed only on netns exit, so use disable_delayed_work_sync() to disable the work instead of adding more synchronization mechanisms. As for the svc_table, it is destroyed when the services are deleted, so we must be sure that netns exit is not called yet (the check for 'enable') and the work is not canceled by checking all under same mutex lock. Also, use WRITE_ONCE when updating the sysctl vars as we already read them with READ_ONCE. Link: https://sashiko.dev/#/patchset/20260410112352.23599-1-fw%40strlen.de Fixes: 8d7de54 ("ipvs: add conn_lfactor and svc_lfactor sysctl vars") Signed-off-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent afbd961 commit f2da9a9

2 files changed

Lines changed: 10 additions & 4 deletions

File tree

net/netfilter/ipvs/ip_vs_conn.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1835,7 +1835,7 @@ static void ip_vs_conn_flush(struct netns_ipvs *ipvs)
18351835

18361836
if (!rcu_dereference_protected(ipvs->conn_tab, 1))
18371837
return;
1838-
cancel_delayed_work_sync(&ipvs->conn_resize_work);
1838+
disable_delayed_work_sync(&ipvs->conn_resize_work);
18391839
if (!atomic_read(&ipvs->conn_count))
18401840
goto unreg;
18411841

net/netfilter/ipvs/ip_vs_ctl.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2469,7 +2469,7 @@ static int ipvs_proc_conn_lfactor(const struct ctl_table *table, int write,
24692469
if (val < -8 || val > 8) {
24702470
ret = -EINVAL;
24712471
} else {
2472-
*valp = val;
2472+
WRITE_ONCE(*valp, val);
24732473
if (rcu_access_pointer(ipvs->conn_tab))
24742474
mod_delayed_work(system_unbound_wq,
24752475
&ipvs->conn_resize_work, 0);
@@ -2496,10 +2496,16 @@ static int ipvs_proc_svc_lfactor(const struct ctl_table *table, int write,
24962496
if (val < -8 || val > 8) {
24972497
ret = -EINVAL;
24982498
} else {
2499-
*valp = val;
2500-
if (rcu_access_pointer(ipvs->svc_table))
2499+
mutex_lock(&ipvs->service_mutex);
2500+
WRITE_ONCE(*valp, val);
2501+
/* Make sure the services are present */
2502+
if (rcu_access_pointer(ipvs->svc_table) &&
2503+
READ_ONCE(ipvs->enable) &&
2504+
!test_bit(IP_VS_WORK_SVC_NORESIZE,
2505+
&ipvs->work_flags))
25012506
mod_delayed_work(system_unbound_wq,
25022507
&ipvs->svc_resize_work, 0);
2508+
mutex_unlock(&ipvs->service_mutex);
25032509
}
25042510
}
25052511
return ret;

0 commit comments

Comments
 (0)