diff options
author | David S. Miller <davem@davemloft.net> | 2018-02-14 14:46:33 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-02-14 14:46:33 -0500 |
commit | 080fe7aa18a29781c4db1d77ca5cb1dd4f68fb44 (patch) | |
tree | 9c3fbf6aec977663deaf766bbaaf5f5a8a41a15c /net/tipc/netlink_compat.c | |
parent | 361b1231801944ddecbd0e383420932633cac2d1 (diff) | |
parent | ed4ffdfec26dfe1bb02435afd1e01f61426f7212 (diff) |
Merge branch 'tipc-locking-fixes'
Ying Xue says:
====================
tipc: Fix missing RTNL lock protection during setting link properties
At present it's unsafe to configure link properties through netlink
as the entire setting process is not under RTNL lock protection. Now
TIPC supports two different sets of netlink APIs at the same time, and
they share the same set of backend functions to configure bearer,
media and net properties. In order to solve the missing RTNL issue,
we have to make the whole __tipc_nl_compat_doit() protected by RTNL,
which means any function called within it cannot take RTNL any more.
So in the series we first introduce the following new functions which
doesn't hold RTNl lock:
- __tipc_nl_bearer_disable()
- __tipc_nl_bearer_enable()
- __tipc_nl_bearer_set()
- __tipc_nl_media_set()
- __tipc_nl_net_set()
Meanwhile, __tipc_nl_compat_doit() has been reconstructed to minimize
the time of holding RTNL lock.
Changes in v4:
- Per suggestion of Kirill Tkhai, divided original big one patch into
seven small ones so that they can be easily reviewed.
Changes in v3:
- Optimized return method of __tipc_nl_bearer_enable() regarding
the comments from David M and Kirill Tkhai
- Moved the allocations of memory in __tipc_nl_compat_doit() out
of RTNL lock to minimize the time of holding RTNL lock according
to the suggestion of Kirill Tkhai.
Changes in v2:
- The whole operation of setting bearer/media properties has been
protected under RTNL, as per feedback from David M.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/netlink_compat.c')
-rw-r--r-- | net/tipc/netlink_compat.c | 43 |
1 files changed, 23 insertions, 20 deletions
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index e48f0b2c01b9..4492cda45566 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c | |||
@@ -285,10 +285,6 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd, | |||
285 | if (!trans_buf) | 285 | if (!trans_buf) |
286 | return -ENOMEM; | 286 | return -ENOMEM; |
287 | 287 | ||
288 | err = (*cmd->transcode)(cmd, trans_buf, msg); | ||
289 | if (err) | ||
290 | goto trans_out; | ||
291 | |||
292 | attrbuf = kmalloc((tipc_genl_family.maxattr + 1) * | 288 | attrbuf = kmalloc((tipc_genl_family.maxattr + 1) * |
293 | sizeof(struct nlattr *), GFP_KERNEL); | 289 | sizeof(struct nlattr *), GFP_KERNEL); |
294 | if (!attrbuf) { | 290 | if (!attrbuf) { |
@@ -296,27 +292,34 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd, | |||
296 | goto trans_out; | 292 | goto trans_out; |
297 | } | 293 | } |
298 | 294 | ||
299 | err = nla_parse(attrbuf, tipc_genl_family.maxattr, | ||
300 | (const struct nlattr *)trans_buf->data, | ||
301 | trans_buf->len, NULL, NULL); | ||
302 | if (err) | ||
303 | goto parse_out; | ||
304 | |||
305 | doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 295 | doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
306 | if (!doit_buf) { | 296 | if (!doit_buf) { |
307 | err = -ENOMEM; | 297 | err = -ENOMEM; |
308 | goto parse_out; | 298 | goto attrbuf_out; |
309 | } | 299 | } |
310 | 300 | ||
311 | doit_buf->sk = msg->dst_sk; | ||
312 | |||
313 | memset(&info, 0, sizeof(info)); | 301 | memset(&info, 0, sizeof(info)); |
314 | info.attrs = attrbuf; | 302 | info.attrs = attrbuf; |
315 | 303 | ||
304 | rtnl_lock(); | ||
305 | err = (*cmd->transcode)(cmd, trans_buf, msg); | ||
306 | if (err) | ||
307 | goto doit_out; | ||
308 | |||
309 | err = nla_parse(attrbuf, tipc_genl_family.maxattr, | ||
310 | (const struct nlattr *)trans_buf->data, | ||
311 | trans_buf->len, NULL, NULL); | ||
312 | if (err) | ||
313 | goto doit_out; | ||
314 | |||
315 | doit_buf->sk = msg->dst_sk; | ||
316 | |||
316 | err = (*cmd->doit)(doit_buf, &info); | 317 | err = (*cmd->doit)(doit_buf, &info); |
318 | doit_out: | ||
319 | rtnl_unlock(); | ||
317 | 320 | ||
318 | kfree_skb(doit_buf); | 321 | kfree_skb(doit_buf); |
319 | parse_out: | 322 | attrbuf_out: |
320 | kfree(attrbuf); | 323 | kfree(attrbuf); |
321 | trans_out: | 324 | trans_out: |
322 | kfree_skb(trans_buf); | 325 | kfree_skb(trans_buf); |
@@ -722,13 +725,13 @@ static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd, | |||
722 | 725 | ||
723 | media = tipc_media_find(lc->name); | 726 | media = tipc_media_find(lc->name); |
724 | if (media) { | 727 | if (media) { |
725 | cmd->doit = &tipc_nl_media_set; | 728 | cmd->doit = &__tipc_nl_media_set; |
726 | return tipc_nl_compat_media_set(skb, msg); | 729 | return tipc_nl_compat_media_set(skb, msg); |
727 | } | 730 | } |
728 | 731 | ||
729 | bearer = tipc_bearer_find(msg->net, lc->name); | 732 | bearer = tipc_bearer_find(msg->net, lc->name); |
730 | if (bearer) { | 733 | if (bearer) { |
731 | cmd->doit = &tipc_nl_bearer_set; | 734 | cmd->doit = &__tipc_nl_bearer_set; |
732 | return tipc_nl_compat_bearer_set(skb, msg); | 735 | return tipc_nl_compat_bearer_set(skb, msg); |
733 | } | 736 | } |
734 | 737 | ||
@@ -1089,12 +1092,12 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg) | |||
1089 | return tipc_nl_compat_dumpit(&dump, msg); | 1092 | return tipc_nl_compat_dumpit(&dump, msg); |
1090 | case TIPC_CMD_ENABLE_BEARER: | 1093 | case TIPC_CMD_ENABLE_BEARER: |
1091 | msg->req_type = TIPC_TLV_BEARER_CONFIG; | 1094 | msg->req_type = TIPC_TLV_BEARER_CONFIG; |
1092 | doit.doit = tipc_nl_bearer_enable; | 1095 | doit.doit = __tipc_nl_bearer_enable; |
1093 | doit.transcode = tipc_nl_compat_bearer_enable; | 1096 | doit.transcode = tipc_nl_compat_bearer_enable; |
1094 | return tipc_nl_compat_doit(&doit, msg); | 1097 | return tipc_nl_compat_doit(&doit, msg); |
1095 | case TIPC_CMD_DISABLE_BEARER: | 1098 | case TIPC_CMD_DISABLE_BEARER: |
1096 | msg->req_type = TIPC_TLV_BEARER_NAME; | 1099 | msg->req_type = TIPC_TLV_BEARER_NAME; |
1097 | doit.doit = tipc_nl_bearer_disable; | 1100 | doit.doit = __tipc_nl_bearer_disable; |
1098 | doit.transcode = tipc_nl_compat_bearer_disable; | 1101 | doit.transcode = tipc_nl_compat_bearer_disable; |
1099 | return tipc_nl_compat_doit(&doit, msg); | 1102 | return tipc_nl_compat_doit(&doit, msg); |
1100 | case TIPC_CMD_SHOW_LINK_STATS: | 1103 | case TIPC_CMD_SHOW_LINK_STATS: |
@@ -1148,12 +1151,12 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg) | |||
1148 | return tipc_nl_compat_dumpit(&dump, msg); | 1151 | return tipc_nl_compat_dumpit(&dump, msg); |
1149 | case TIPC_CMD_SET_NODE_ADDR: | 1152 | case TIPC_CMD_SET_NODE_ADDR: |
1150 | msg->req_type = TIPC_TLV_NET_ADDR; | 1153 | msg->req_type = TIPC_TLV_NET_ADDR; |
1151 | doit.doit = tipc_nl_net_set; | 1154 | doit.doit = __tipc_nl_net_set; |
1152 | doit.transcode = tipc_nl_compat_net_set; | 1155 | doit.transcode = tipc_nl_compat_net_set; |
1153 | return tipc_nl_compat_doit(&doit, msg); | 1156 | return tipc_nl_compat_doit(&doit, msg); |
1154 | case TIPC_CMD_SET_NETID: | 1157 | case TIPC_CMD_SET_NETID: |
1155 | msg->req_type = TIPC_TLV_UNSIGNED; | 1158 | msg->req_type = TIPC_TLV_UNSIGNED; |
1156 | doit.doit = tipc_nl_net_set; | 1159 | doit.doit = __tipc_nl_net_set; |
1157 | doit.transcode = tipc_nl_compat_net_set; | 1160 | doit.transcode = tipc_nl_compat_net_set; |
1158 | return tipc_nl_compat_doit(&doit, msg); | 1161 | return tipc_nl_compat_doit(&doit, msg); |
1159 | case TIPC_CMD_GET_NETID: | 1162 | case TIPC_CMD_GET_NETID: |