| From 9b98e1899085a9ed649120bd7398a9e1de25b415 Mon Sep 17 00:00:00 2001 |
| From: Taehee Yoo <ap420073@gmail.com> |
| Date: Fri, 13 Mar 2020 06:50:14 +0000 |
| Subject: [PATCH] hsr: use rcu_read_lock() in hsr_get_node_{list/status}() |
| |
| commit 173756b86803655d70af7732079b3aa935e6ab68 upstream. |
| |
| hsr_get_node_{list/status}() are not under rtnl_lock() because |
| they are callback functions of generic netlink. |
| But they use __dev_get_by_index() without rtnl_lock(). |
| So, it would use unsafe data. |
| In order to fix it, rcu_read_lock() and dev_get_by_index_rcu() |
| are used instead of __dev_get_by_index(). |
| |
| Fixes: f421436a591d ("net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)") |
| Signed-off-by: Taehee Yoo <ap420073@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c |
| index 27dc65d7de67..002f341f3564 100644 |
| --- a/net/hsr/hsr_framereg.c |
| +++ b/net/hsr/hsr_framereg.c |
| @@ -482,12 +482,9 @@ int hsr_get_node_data(struct hsr_priv *hsr, |
| struct hsr_port *port; |
| unsigned long tdiff; |
| |
| - rcu_read_lock(); |
| node = find_node_by_addr_A(&hsr->node_db, addr); |
| - if (!node) { |
| - rcu_read_unlock(); |
| - return -ENOENT; /* No such entry */ |
| - } |
| + if (!node) |
| + return -ENOENT; |
| |
| ether_addr_copy(addr_b, node->macaddress_B); |
| |
| @@ -522,7 +519,5 @@ int hsr_get_node_data(struct hsr_priv *hsr, |
| *addr_b_ifindex = -1; |
| } |
| |
| - rcu_read_unlock(); |
| - |
| return 0; |
| } |
| diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c |
| index 8dc0547f01d0..d6760df2ad1f 100644 |
| --- a/net/hsr/hsr_netlink.c |
| +++ b/net/hsr/hsr_netlink.c |
| @@ -251,15 +251,16 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) |
| if (!na) |
| goto invalid; |
| |
| - hsr_dev = __dev_get_by_index(genl_info_net(info), |
| - nla_get_u32(info->attrs[HSR_A_IFINDEX])); |
| + rcu_read_lock(); |
| + hsr_dev = dev_get_by_index_rcu(genl_info_net(info), |
| + nla_get_u32(info->attrs[HSR_A_IFINDEX])); |
| if (!hsr_dev) |
| - goto invalid; |
| + goto rcu_unlock; |
| if (!is_hsr_master(hsr_dev)) |
| - goto invalid; |
| + goto rcu_unlock; |
| |
| /* Send reply */ |
| - skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
| + skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); |
| if (!skb_out) { |
| res = -ENOMEM; |
| goto fail; |
| @@ -313,12 +314,10 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) |
| res = nla_put_u16(skb_out, HSR_A_IF1_SEQ, hsr_node_if1_seq); |
| if (res < 0) |
| goto nla_put_failure; |
| - rcu_read_lock(); |
| port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); |
| if (port) |
| res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX, |
| port->dev->ifindex); |
| - rcu_read_unlock(); |
| if (res < 0) |
| goto nla_put_failure; |
| |
| @@ -328,20 +327,22 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) |
| res = nla_put_u16(skb_out, HSR_A_IF2_SEQ, hsr_node_if2_seq); |
| if (res < 0) |
| goto nla_put_failure; |
| - rcu_read_lock(); |
| port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); |
| if (port) |
| res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX, |
| port->dev->ifindex); |
| - rcu_read_unlock(); |
| if (res < 0) |
| goto nla_put_failure; |
| |
| + rcu_read_unlock(); |
| + |
| genlmsg_end(skb_out, msg_head); |
| genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid); |
| |
| return 0; |
| |
| +rcu_unlock: |
| + rcu_read_unlock(); |
| invalid: |
| netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL); |
| return 0; |
| @@ -351,6 +352,7 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) |
| /* Fall through */ |
| |
| fail: |
| + rcu_read_unlock(); |
| return res; |
| } |
| |
| @@ -377,15 +379,16 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) |
| if (!na) |
| goto invalid; |
| |
| - hsr_dev = __dev_get_by_index(genl_info_net(info), |
| - nla_get_u32(info->attrs[HSR_A_IFINDEX])); |
| + rcu_read_lock(); |
| + hsr_dev = dev_get_by_index_rcu(genl_info_net(info), |
| + nla_get_u32(info->attrs[HSR_A_IFINDEX])); |
| if (!hsr_dev) |
| - goto invalid; |
| + goto rcu_unlock; |
| if (!is_hsr_master(hsr_dev)) |
| - goto invalid; |
| + goto rcu_unlock; |
| |
| /* Send reply */ |
| - skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
| + skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); |
| if (!skb_out) { |
| res = -ENOMEM; |
| goto fail; |
| @@ -405,14 +408,11 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) |
| |
| hsr = netdev_priv(hsr_dev); |
| |
| - rcu_read_lock(); |
| pos = hsr_get_next_node(hsr, NULL, addr); |
| while (pos) { |
| res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, addr); |
| - if (res < 0) { |
| - rcu_read_unlock(); |
| + if (res < 0) |
| goto nla_put_failure; |
| - } |
| pos = hsr_get_next_node(hsr, pos, addr); |
| } |
| rcu_read_unlock(); |
| @@ -422,6 +422,8 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) |
| |
| return 0; |
| |
| +rcu_unlock: |
| + rcu_read_unlock(); |
| invalid: |
| netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL); |
| return 0; |
| @@ -431,6 +433,7 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) |
| /* Fall through */ |
| |
| fail: |
| + rcu_read_unlock(); |
| return res; |
| } |
| |
| -- |
| 2.7.4 |
| |