Simon Horman says:

====================
IPVS fixes for v5.4

* Eric Dumazet resolves a race condition in switching the defense level
* Davide Caratti resolves a race condition in module removal
====================

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Pablo Neira Ayuso 2019-10-26 12:42:45 +02:00
commit 52b33b4f81
6 changed files with 36 additions and 25 deletions

View File

@ -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 */

View File

@ -193,21 +193,29 @@ struct ip_vs_app *register_ip_vs_app(struct netns_ipvs *ipvs, struct ip_vs_app *
mutex_lock(&__ip_vs_app_mutex); mutex_lock(&__ip_vs_app_mutex);
/* increase the module use count */
if (!ip_vs_use_count_inc()) {
err = -ENOENT;
goto out_unlock;
}
list_for_each_entry(a, &ipvs->app_list, a_list) { list_for_each_entry(a, &ipvs->app_list, a_list) {
if (!strcmp(app->name, a->name)) { if (!strcmp(app->name, a->name)) {
err = -EEXIST; err = -EEXIST;
/* decrease the module use count */
ip_vs_use_count_dec();
goto out_unlock; goto out_unlock;
} }
} }
a = kmemdup(app, sizeof(*app), GFP_KERNEL); a = kmemdup(app, sizeof(*app), GFP_KERNEL);
if (!a) { if (!a) {
err = -ENOMEM; err = -ENOMEM;
/* decrease the module use count */
ip_vs_use_count_dec();
goto out_unlock; goto out_unlock;
} }
INIT_LIST_HEAD(&a->incs_list); INIT_LIST_HEAD(&a->incs_list);
list_add(&a->a_list, &ipvs->app_list); list_add(&a->a_list, &ipvs->app_list);
/* increase the module use count */
ip_vs_use_count_inc();
out_unlock: out_unlock:
mutex_unlock(&__ip_vs_app_mutex); mutex_unlock(&__ip_vs_app_mutex);

View File

@ -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);
@ -1275,7 +1274,8 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u,
struct ip_vs_service *svc = NULL; struct ip_vs_service *svc = NULL;
/* increase the module use count */ /* increase the module use count */
ip_vs_use_count_inc(); if (!ip_vs_use_count_inc())
return -ENOPROTOOPT;
/* Lookup the scheduler by 'u->sched_name' */ /* Lookup the scheduler by 'u->sched_name' */
if (strcmp(u->sched_name, "none")) { if (strcmp(u->sched_name, "none")) {
@ -2435,9 +2435,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
if (copy_from_user(arg, user, len) != 0) if (copy_from_user(arg, user, len) != 0)
return -EFAULT; return -EFAULT;
/* increase the module use count */
ip_vs_use_count_inc();
/* Handle daemons since they have another lock */ /* Handle daemons since they have another lock */
if (cmd == IP_VS_SO_SET_STARTDAEMON || if (cmd == IP_VS_SO_SET_STARTDAEMON ||
cmd == IP_VS_SO_SET_STOPDAEMON) { cmd == IP_VS_SO_SET_STOPDAEMON) {
@ -2450,13 +2447,13 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
ret = -EINVAL; ret = -EINVAL;
if (strscpy(cfg.mcast_ifn, dm->mcast_ifn, if (strscpy(cfg.mcast_ifn, dm->mcast_ifn,
sizeof(cfg.mcast_ifn)) <= 0) sizeof(cfg.mcast_ifn)) <= 0)
goto out_dec; return ret;
cfg.syncid = dm->syncid; cfg.syncid = dm->syncid;
ret = start_sync_thread(ipvs, &cfg, dm->state); ret = start_sync_thread(ipvs, &cfg, dm->state);
} else { } else {
ret = stop_sync_thread(ipvs, dm->state); ret = stop_sync_thread(ipvs, dm->state);
} }
goto out_dec; return ret;
} }
mutex_lock(&__ip_vs_mutex); mutex_lock(&__ip_vs_mutex);
@ -2551,10 +2548,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
out_unlock: out_unlock:
mutex_unlock(&__ip_vs_mutex); mutex_unlock(&__ip_vs_mutex);
out_dec:
/* decrease the module use count */
ip_vs_use_count_dec();
return ret; return ret;
} }

View File

@ -68,7 +68,8 @@ int register_ip_vs_pe(struct ip_vs_pe *pe)
struct ip_vs_pe *tmp; struct ip_vs_pe *tmp;
/* increase the module use count */ /* increase the module use count */
ip_vs_use_count_inc(); if (!ip_vs_use_count_inc())
return -ENOENT;
mutex_lock(&ip_vs_pe_mutex); mutex_lock(&ip_vs_pe_mutex);
/* Make sure that the pe with this name doesn't exist /* Make sure that the pe with this name doesn't exist

View File

@ -179,7 +179,8 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
} }
/* increase the module use count */ /* increase the module use count */
ip_vs_use_count_inc(); if (!ip_vs_use_count_inc())
return -ENOENT;
mutex_lock(&ip_vs_sched_mutex); mutex_lock(&ip_vs_sched_mutex);

View File

@ -1762,6 +1762,10 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %zd bytes\n", IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %zd bytes\n",
sizeof(struct ip_vs_sync_conn_v0)); sizeof(struct ip_vs_sync_conn_v0));
/* increase the module use count */
if (!ip_vs_use_count_inc())
return -ENOPROTOOPT;
/* Do not hold one mutex and then to block on another */ /* Do not hold one mutex and then to block on another */
for (;;) { for (;;) {
rtnl_lock(); rtnl_lock();
@ -1892,9 +1896,6 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
mutex_unlock(&ipvs->sync_mutex); mutex_unlock(&ipvs->sync_mutex);
rtnl_unlock(); rtnl_unlock();
/* increase the module use count */
ip_vs_use_count_inc();
return 0; return 0;
out: out:
@ -1924,11 +1925,17 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
} }
kfree(ti); kfree(ti);
} }
/* decrease the module use count */
ip_vs_use_count_dec();
return result; return result;
out_early: out_early:
mutex_unlock(&ipvs->sync_mutex); mutex_unlock(&ipvs->sync_mutex);
rtnl_unlock(); rtnl_unlock();
/* decrease the module use count */
ip_vs_use_count_dec();
return result; return result;
} }