Skip to content

Commit e0b26cc

Browse files
Julian Anastasovhorms
authored andcommitted
ipvs: call rtnl_lock early
When the sync damon is started we need to hold rtnl lock while calling ip_mc_join_group. Currently, we have a wrong locking order because the correct one is rtnl_lock->__ip_vs_mutex. It is implied from the usage of __ip_vs_mutex in ip_vs_dst_event() which is called under rtnl lock during NETDEV_* notifications. Fix the problem by calling rtnl_lock early only for the start_sync_thread call. As a bonus this fixes the usage __dev_get_by_name which was not called under rtnl lock. This patch actually extends and depends on commit 54ff9ef ("ipv4, ipv6: kill ip_mc_{join, leave}_group and ipv6_sock_mc_{join, drop}"). Signed-off-by: Julian Anastasov <[email protected]> Signed-off-by: Simon Horman <[email protected]>
1 parent eefa32d commit e0b26cc

File tree

2 files changed

+33
-19
lines changed

2 files changed

+33
-19
lines changed

net/netfilter/ipvs/ip_vs_ctl.c

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2335,13 +2335,18 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
23352335
cmd == IP_VS_SO_SET_STOPDAEMON) {
23362336
struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;
23372337

2338-
mutex_lock(&ipvs->sync_mutex);
2339-
if (cmd == IP_VS_SO_SET_STARTDAEMON)
2338+
if (cmd == IP_VS_SO_SET_STARTDAEMON) {
2339+
rtnl_lock();
2340+
mutex_lock(&ipvs->sync_mutex);
23402341
ret = start_sync_thread(net, dm->state, dm->mcast_ifn,
23412342
dm->syncid);
2342-
else
2343+
mutex_unlock(&ipvs->sync_mutex);
2344+
rtnl_unlock();
2345+
} else {
2346+
mutex_lock(&ipvs->sync_mutex);
23432347
ret = stop_sync_thread(net, dm->state);
2344-
mutex_unlock(&ipvs->sync_mutex);
2348+
mutex_unlock(&ipvs->sync_mutex);
2349+
}
23452350
goto out_dec;
23462351
}
23472352

@@ -3342,6 +3347,9 @@ static int ip_vs_genl_dump_daemons(struct sk_buff *skb,
33423347

33433348
static int ip_vs_genl_new_daemon(struct net *net, struct nlattr **attrs)
33443349
{
3350+
struct netns_ipvs *ipvs = net_ipvs(net);
3351+
int ret;
3352+
33453353
if (!(attrs[IPVS_DAEMON_ATTR_STATE] &&
33463354
attrs[IPVS_DAEMON_ATTR_MCAST_IFN] &&
33473355
attrs[IPVS_DAEMON_ATTR_SYNC_ID]))
@@ -3353,19 +3361,30 @@ static int ip_vs_genl_new_daemon(struct net *net, struct nlattr **attrs)
33533361
if (net_ipvs(net)->mixed_address_family_dests > 0)
33543362
return -EINVAL;
33553363

3356-
return start_sync_thread(net,
3357-
nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]),
3358-
nla_data(attrs[IPVS_DAEMON_ATTR_MCAST_IFN]),
3359-
nla_get_u32(attrs[IPVS_DAEMON_ATTR_SYNC_ID]));
3364+
rtnl_lock();
3365+
mutex_lock(&ipvs->sync_mutex);
3366+
ret = start_sync_thread(net,
3367+
nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]),
3368+
nla_data(attrs[IPVS_DAEMON_ATTR_MCAST_IFN]),
3369+
nla_get_u32(attrs[IPVS_DAEMON_ATTR_SYNC_ID]));
3370+
mutex_unlock(&ipvs->sync_mutex);
3371+
rtnl_unlock();
3372+
return ret;
33603373
}
33613374

33623375
static int ip_vs_genl_del_daemon(struct net *net, struct nlattr **attrs)
33633376
{
3377+
struct netns_ipvs *ipvs = net_ipvs(net);
3378+
int ret;
3379+
33643380
if (!attrs[IPVS_DAEMON_ATTR_STATE])
33653381
return -EINVAL;
33663382

3367-
return stop_sync_thread(net,
3368-
nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]));
3383+
mutex_lock(&ipvs->sync_mutex);
3384+
ret = stop_sync_thread(net,
3385+
nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]));
3386+
mutex_unlock(&ipvs->sync_mutex);
3387+
return ret;
33693388
}
33703389

33713390
static int ip_vs_genl_set_config(struct net *net, struct nlattr **attrs)
@@ -3389,7 +3408,7 @@ static int ip_vs_genl_set_config(struct net *net, struct nlattr **attrs)
33893408

33903409
static int ip_vs_genl_set_daemon(struct sk_buff *skb, struct genl_info *info)
33913410
{
3392-
int ret = 0, cmd;
3411+
int ret = -EINVAL, cmd;
33933412
struct net *net;
33943413
struct netns_ipvs *ipvs;
33953414

@@ -3400,22 +3419,19 @@ static int ip_vs_genl_set_daemon(struct sk_buff *skb, struct genl_info *info)
34003419
if (cmd == IPVS_CMD_NEW_DAEMON || cmd == IPVS_CMD_DEL_DAEMON) {
34013420
struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1];
34023421

3403-
mutex_lock(&ipvs->sync_mutex);
34043422
if (!info->attrs[IPVS_CMD_ATTR_DAEMON] ||
34053423
nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX,
34063424
info->attrs[IPVS_CMD_ATTR_DAEMON],
3407-
ip_vs_daemon_policy)) {
3408-
ret = -EINVAL;
3425+
ip_vs_daemon_policy))
34093426
goto out;
3410-
}
34113427

34123428
if (cmd == IPVS_CMD_NEW_DAEMON)
34133429
ret = ip_vs_genl_new_daemon(net, daemon_attrs);
34143430
else
34153431
ret = ip_vs_genl_del_daemon(net, daemon_attrs);
3416-
out:
3417-
mutex_unlock(&ipvs->sync_mutex);
34183432
}
3433+
3434+
out:
34193435
return ret;
34203436
}
34213437

net/netfilter/ipvs/ip_vs_sync.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,11 +1405,9 @@ join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname)
14051405

14061406
mreq.imr_ifindex = dev->ifindex;
14071407

1408-
rtnl_lock();
14091408
lock_sock(sk);
14101409
ret = ip_mc_join_group(sk, &mreq);
14111410
release_sock(sk);
1412-
rtnl_unlock();
14131411

14141412
return ret;
14151413
}

0 commit comments

Comments
 (0)