aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-02-14 14:46:33 -0500
committerDavid S. Miller <davem@davemloft.net>2018-02-14 14:46:33 -0500
commit080fe7aa18a29781c4db1d77ca5cb1dd4f68fb44 (patch)
tree9c3fbf6aec977663deaf766bbaaf5f5a8a41a15c
parent361b1231801944ddecbd0e383420932633cac2d1 (diff)
parented4ffdfec26dfe1bb02435afd1e01f61426f7212 (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>
-rw-r--r--net/tipc/bearer.c82
-rw-r--r--net/tipc/bearer.h4
-rw-r--r--net/tipc/net.c15
-rw-r--r--net/tipc/net.h1
-rw-r--r--net/tipc/netlink_compat.c43
5 files changed, 91 insertions, 54 deletions
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index c8001471da6c..3e3dce3d4c63 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -813,7 +813,7 @@ err_out:
813 return err; 813 return err;
814} 814}
815 815
816int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info) 816int __tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
817{ 817{
818 int err; 818 int err;
819 char *name; 819 char *name;
@@ -835,20 +835,27 @@ int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
835 835
836 name = nla_data(attrs[TIPC_NLA_BEARER_NAME]); 836 name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
837 837
838 rtnl_lock();
839 bearer = tipc_bearer_find(net, name); 838 bearer = tipc_bearer_find(net, name);
840 if (!bearer) { 839 if (!bearer)
841 rtnl_unlock();
842 return -EINVAL; 840 return -EINVAL;
843 }
844 841
845 bearer_disable(net, bearer); 842 bearer_disable(net, bearer);
846 rtnl_unlock();
847 843
848 return 0; 844 return 0;
849} 845}
850 846
851int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info) 847int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
848{
849 int err;
850
851 rtnl_lock();
852 err = __tipc_nl_bearer_disable(skb, info);
853 rtnl_unlock();
854
855 return err;
856}
857
858int __tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
852{ 859{
853 int err; 860 int err;
854 char *bearer; 861 char *bearer;
@@ -890,15 +897,18 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
890 prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); 897 prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
891 } 898 }
892 899
900 return tipc_enable_bearer(net, bearer, domain, prio, attrs);
901}
902
903int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
904{
905 int err;
906
893 rtnl_lock(); 907 rtnl_lock();
894 err = tipc_enable_bearer(net, bearer, domain, prio, attrs); 908 err = __tipc_nl_bearer_enable(skb, info);
895 if (err) {
896 rtnl_unlock();
897 return err;
898 }
899 rtnl_unlock(); 909 rtnl_unlock();
900 910
901 return 0; 911 return err;
902} 912}
903 913
904int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info) 914int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info)
@@ -944,7 +954,7 @@ int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info)
944 return 0; 954 return 0;
945} 955}
946 956
947int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info) 957int __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
948{ 958{
949 int err; 959 int err;
950 char *name; 960 char *name;
@@ -965,22 +975,17 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
965 return -EINVAL; 975 return -EINVAL;
966 name = nla_data(attrs[TIPC_NLA_BEARER_NAME]); 976 name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
967 977
968 rtnl_lock();
969 b = tipc_bearer_find(net, name); 978 b = tipc_bearer_find(net, name);
970 if (!b) { 979 if (!b)
971 rtnl_unlock();
972 return -EINVAL; 980 return -EINVAL;
973 }
974 981
975 if (attrs[TIPC_NLA_BEARER_PROP]) { 982 if (attrs[TIPC_NLA_BEARER_PROP]) {
976 struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; 983 struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
977 984
978 err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP], 985 err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP],
979 props); 986 props);
980 if (err) { 987 if (err)
981 rtnl_unlock();
982 return err; 988 return err;
983 }
984 989
985 if (props[TIPC_NLA_PROP_TOL]) 990 if (props[TIPC_NLA_PROP_TOL])
986 b->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]); 991 b->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
@@ -989,11 +994,21 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
989 if (props[TIPC_NLA_PROP_WIN]) 994 if (props[TIPC_NLA_PROP_WIN])
990 b->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 995 b->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
991 } 996 }
992 rtnl_unlock();
993 997
994 return 0; 998 return 0;
995} 999}
996 1000
1001int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
1002{
1003 int err;
1004
1005 rtnl_lock();
1006 err = __tipc_nl_bearer_set(skb, info);
1007 rtnl_unlock();
1008
1009 return err;
1010}
1011
997static int __tipc_nl_add_media(struct tipc_nl_msg *msg, 1012static int __tipc_nl_add_media(struct tipc_nl_msg *msg,
998 struct tipc_media *media, int nlflags) 1013 struct tipc_media *media, int nlflags)
999{ 1014{
@@ -1115,7 +1130,7 @@ err_out:
1115 return err; 1130 return err;
1116} 1131}
1117 1132
1118int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info) 1133int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
1119{ 1134{
1120 int err; 1135 int err;
1121 char *name; 1136 char *name;
@@ -1133,22 +1148,17 @@ int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
1133 return -EINVAL; 1148 return -EINVAL;
1134 name = nla_data(attrs[TIPC_NLA_MEDIA_NAME]); 1149 name = nla_data(attrs[TIPC_NLA_MEDIA_NAME]);
1135 1150
1136 rtnl_lock();
1137 m = tipc_media_find(name); 1151 m = tipc_media_find(name);
1138 if (!m) { 1152 if (!m)
1139 rtnl_unlock();
1140 return -EINVAL; 1153 return -EINVAL;
1141 }
1142 1154
1143 if (attrs[TIPC_NLA_MEDIA_PROP]) { 1155 if (attrs[TIPC_NLA_MEDIA_PROP]) {
1144 struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; 1156 struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
1145 1157
1146 err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_MEDIA_PROP], 1158 err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_MEDIA_PROP],
1147 props); 1159 props);
1148 if (err) { 1160 if (err)
1149 rtnl_unlock();
1150 return err; 1161 return err;
1151 }
1152 1162
1153 if (props[TIPC_NLA_PROP_TOL]) 1163 if (props[TIPC_NLA_PROP_TOL])
1154 m->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]); 1164 m->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
@@ -1157,7 +1167,17 @@ int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
1157 if (props[TIPC_NLA_PROP_WIN]) 1167 if (props[TIPC_NLA_PROP_WIN])
1158 m->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 1168 m->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
1159 } 1169 }
1160 rtnl_unlock();
1161 1170
1162 return 0; 1171 return 0;
1163} 1172}
1173
1174int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
1175{
1176 int err;
1177
1178 rtnl_lock();
1179 err = __tipc_nl_media_set(skb, info);
1180 rtnl_unlock();
1181
1182 return err;
1183}
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 42d6eeeb646d..a53613d95bc9 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -188,15 +188,19 @@ extern struct tipc_media udp_media_info;
188#endif 188#endif
189 189
190int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info); 190int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info);
191int __tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info);
191int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info); 192int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info);
193int __tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info);
192int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb); 194int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb);
193int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info); 195int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info);
194int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info); 196int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info);
197int __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info);
195int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info); 198int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info);
196 199
197int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb); 200int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb);
198int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info); 201int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info);
199int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info); 202int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info);
203int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info);
200 204
201int tipc_media_set_priority(const char *name, u32 new_value); 205int tipc_media_set_priority(const char *name, u32 new_value);
202int tipc_media_set_window(const char *name, u32 new_value); 206int tipc_media_set_window(const char *name, u32 new_value);
diff --git a/net/tipc/net.c b/net/tipc/net.c
index 719c5924b638..1a2fde0d6f61 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -200,7 +200,7 @@ out:
200 return skb->len; 200 return skb->len;
201} 201}
202 202
203int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info) 203int __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
204{ 204{
205 struct net *net = sock_net(skb->sk); 205 struct net *net = sock_net(skb->sk);
206 struct tipc_net *tn = net_generic(net, tipc_net_id); 206 struct tipc_net *tn = net_generic(net, tipc_net_id);
@@ -241,10 +241,19 @@ int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
241 if (!tipc_addr_node_valid(addr)) 241 if (!tipc_addr_node_valid(addr))
242 return -EINVAL; 242 return -EINVAL;
243 243
244 rtnl_lock();
245 tipc_net_start(net, addr); 244 tipc_net_start(net, addr);
246 rtnl_unlock();
247 } 245 }
248 246
249 return 0; 247 return 0;
250} 248}
249
250int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
251{
252 int err;
253
254 rtnl_lock();
255 err = __tipc_nl_net_set(skb, info);
256 rtnl_unlock();
257
258 return err;
259}
diff --git a/net/tipc/net.h b/net/tipc/net.h
index c7c254902873..c0306aa2374b 100644
--- a/net/tipc/net.h
+++ b/net/tipc/net.h
@@ -47,5 +47,6 @@ void tipc_net_stop(struct net *net);
47 47
48int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb); 48int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb);
49int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info); 49int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info);
50int __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info);
50 51
51#endif 52#endif
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);
318doit_out:
319 rtnl_unlock();
317 320
318 kfree_skb(doit_buf); 321 kfree_skb(doit_buf);
319parse_out: 322attrbuf_out:
320 kfree(attrbuf); 323 kfree(attrbuf);
321trans_out: 324trans_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: