Skip to content

Commit 173756b

Browse files
TaeheeYoodavem330
authored andcommitted
hsr: use rcu_read_lock() in hsr_get_node_{list/status}()
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: f421436 ("net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)") Signed-off-by: Taehee Yoo <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent dcadaec commit 173756b

File tree

2 files changed

+23
-25
lines changed

2 files changed

+23
-25
lines changed

net/hsr/hsr_framereg.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -482,12 +482,9 @@ int hsr_get_node_data(struct hsr_priv *hsr,
482482
struct hsr_port *port;
483483
unsigned long tdiff;
484484

485-
rcu_read_lock();
486485
node = find_node_by_addr_A(&hsr->node_db, addr);
487-
if (!node) {
488-
rcu_read_unlock();
489-
return -ENOENT; /* No such entry */
490-
}
486+
if (!node)
487+
return -ENOENT;
491488

492489
ether_addr_copy(addr_b, node->macaddress_B);
493490

@@ -522,7 +519,5 @@ int hsr_get_node_data(struct hsr_priv *hsr,
522519
*addr_b_ifindex = -1;
523520
}
524521

525-
rcu_read_unlock();
526-
527522
return 0;
528523
}

net/hsr/hsr_netlink.c

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -251,15 +251,16 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
251251
if (!na)
252252
goto invalid;
253253

254-
hsr_dev = __dev_get_by_index(genl_info_net(info),
255-
nla_get_u32(info->attrs[HSR_A_IFINDEX]));
254+
rcu_read_lock();
255+
hsr_dev = dev_get_by_index_rcu(genl_info_net(info),
256+
nla_get_u32(info->attrs[HSR_A_IFINDEX]));
256257
if (!hsr_dev)
257-
goto invalid;
258+
goto rcu_unlock;
258259
if (!is_hsr_master(hsr_dev))
259-
goto invalid;
260+
goto rcu_unlock;
260261

261262
/* Send reply */
262-
skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
263+
skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
263264
if (!skb_out) {
264265
res = -ENOMEM;
265266
goto fail;
@@ -313,12 +314,10 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
313314
res = nla_put_u16(skb_out, HSR_A_IF1_SEQ, hsr_node_if1_seq);
314315
if (res < 0)
315316
goto nla_put_failure;
316-
rcu_read_lock();
317317
port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A);
318318
if (port)
319319
res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX,
320320
port->dev->ifindex);
321-
rcu_read_unlock();
322321
if (res < 0)
323322
goto nla_put_failure;
324323

@@ -328,20 +327,22 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
328327
res = nla_put_u16(skb_out, HSR_A_IF2_SEQ, hsr_node_if2_seq);
329328
if (res < 0)
330329
goto nla_put_failure;
331-
rcu_read_lock();
332330
port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B);
333331
if (port)
334332
res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX,
335333
port->dev->ifindex);
336-
rcu_read_unlock();
337334
if (res < 0)
338335
goto nla_put_failure;
339336

337+
rcu_read_unlock();
338+
340339
genlmsg_end(skb_out, msg_head);
341340
genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid);
342341

343342
return 0;
344343

344+
rcu_unlock:
345+
rcu_read_unlock();
345346
invalid:
346347
netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
347348
return 0;
@@ -351,6 +352,7 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
351352
/* Fall through */
352353

353354
fail:
355+
rcu_read_unlock();
354356
return res;
355357
}
356358

@@ -377,15 +379,16 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
377379
if (!na)
378380
goto invalid;
379381

380-
hsr_dev = __dev_get_by_index(genl_info_net(info),
381-
nla_get_u32(info->attrs[HSR_A_IFINDEX]));
382+
rcu_read_lock();
383+
hsr_dev = dev_get_by_index_rcu(genl_info_net(info),
384+
nla_get_u32(info->attrs[HSR_A_IFINDEX]));
382385
if (!hsr_dev)
383-
goto invalid;
386+
goto rcu_unlock;
384387
if (!is_hsr_master(hsr_dev))
385-
goto invalid;
388+
goto rcu_unlock;
386389

387390
/* Send reply */
388-
skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
391+
skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
389392
if (!skb_out) {
390393
res = -ENOMEM;
391394
goto fail;
@@ -405,14 +408,11 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
405408

406409
hsr = netdev_priv(hsr_dev);
407410

408-
rcu_read_lock();
409411
pos = hsr_get_next_node(hsr, NULL, addr);
410412
while (pos) {
411413
res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, addr);
412-
if (res < 0) {
413-
rcu_read_unlock();
414+
if (res < 0)
414415
goto nla_put_failure;
415-
}
416416
pos = hsr_get_next_node(hsr, pos, addr);
417417
}
418418
rcu_read_unlock();
@@ -422,6 +422,8 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
422422

423423
return 0;
424424

425+
rcu_unlock:
426+
rcu_read_unlock();
425427
invalid:
426428
netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
427429
return 0;
@@ -431,6 +433,7 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
431433
/* Fall through */
432434

433435
fail:
436+
rcu_read_unlock();
434437
return res;
435438
}
436439

0 commit comments

Comments
 (0)