Skip to content

Commit a428bfc

Browse files
q2venkuba-moo
authored andcommitted
arp: Get dev after calling arp_req_(delete|set|get)().
arp_ioctl() holds rtnl_lock() first regardless of cmd (SIOCDARP, SIOCSARP, and SIOCGARP) to get net_device by __dev_get_by_name() and copy dev->name safely. In the SIOCGARP path, arp_req_get() calls neigh_lookup(), which looks up a neighbour entry under RCU. We will extend the RCU section not to take rtnl_lock() and instead use dev_get_by_name_rcu() for SIOCGARP. As a preparation, let's move __dev_get_by_name() into another function and call it from arp_req_delete(), arp_req_set(), and arp_req_get(). Signed-off-by: Kuniyuki Iwashima <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 51e9ba4 commit a428bfc

File tree

1 file changed

+50
-36
lines changed

1 file changed

+50
-36
lines changed

net/ipv4/arp.c

Lines changed: 50 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,12 +1003,36 @@ static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
10031003
* User level interface (ioctl)
10041004
*/
10051005

1006+
static struct net_device *arp_req_dev_by_name(struct net *net, struct arpreq *r)
1007+
{
1008+
struct net_device *dev;
1009+
1010+
dev = __dev_get_by_name(net, r->arp_dev);
1011+
if (!dev)
1012+
return ERR_PTR(-ENODEV);
1013+
1014+
/* Mmmm... It is wrong... ARPHRD_NETROM == 0 */
1015+
if (!r->arp_ha.sa_family)
1016+
r->arp_ha.sa_family = dev->type;
1017+
1018+
if ((r->arp_flags & ATF_COM) && r->arp_ha.sa_family != dev->type)
1019+
return ERR_PTR(-EINVAL);
1020+
1021+
return dev;
1022+
}
1023+
10061024
static struct net_device *arp_req_dev(struct net *net, struct arpreq *r)
10071025
{
10081026
struct net_device *dev;
10091027
struct rtable *rt;
10101028
__be32 ip;
10111029

1030+
if (r->arp_dev[0])
1031+
return arp_req_dev_by_name(net, r);
1032+
1033+
if (r->arp_flags & ATF_PUBL)
1034+
return NULL;
1035+
10121036
ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
10131037

10141038
rt = ip_route_output(net, ip, 0, 0, 0, RT_SCOPE_LINK);
@@ -1063,21 +1087,20 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
10631087
return arp_req_set_proxy(net, dev, 1);
10641088
}
10651089

1066-
static int arp_req_set(struct net *net, struct arpreq *r,
1067-
struct net_device *dev)
1090+
static int arp_req_set(struct net *net, struct arpreq *r)
10681091
{
10691092
struct neighbour *neigh;
1093+
struct net_device *dev;
10701094
__be32 ip;
10711095
int err;
10721096

1097+
dev = arp_req_dev(net, r);
1098+
if (IS_ERR(dev))
1099+
return PTR_ERR(dev);
1100+
10731101
if (r->arp_flags & ATF_PUBL)
10741102
return arp_req_set_public(net, r, dev);
10751103

1076-
if (!dev) {
1077-
dev = arp_req_dev(net, r);
1078-
if (IS_ERR(dev))
1079-
return PTR_ERR(dev);
1080-
}
10811104
switch (dev->type) {
10821105
#if IS_ENABLED(CONFIG_FDDI)
10831106
case ARPHRD_FDDI:
@@ -1134,10 +1157,18 @@ static unsigned int arp_state_to_flags(struct neighbour *neigh)
11341157
* Get an ARP cache entry.
11351158
*/
11361159

1137-
static int arp_req_get(struct arpreq *r, struct net_device *dev)
1160+
static int arp_req_get(struct net *net, struct arpreq *r)
11381161
{
11391162
__be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
11401163
struct neighbour *neigh;
1164+
struct net_device *dev;
1165+
1166+
if (!r->arp_dev[0])
1167+
return -ENODEV;
1168+
1169+
dev = arp_req_dev_by_name(net, r);
1170+
if (IS_ERR(dev))
1171+
return PTR_ERR(dev);
11411172

11421173
neigh = neigh_lookup(&arp_tbl, &ip, dev);
11431174
if (!neigh)
@@ -1201,20 +1232,20 @@ static int arp_req_delete_public(struct net *net, struct arpreq *r,
12011232
return arp_req_set_proxy(net, dev, 0);
12021233
}
12031234

1204-
static int arp_req_delete(struct net *net, struct arpreq *r,
1205-
struct net_device *dev)
1235+
static int arp_req_delete(struct net *net, struct arpreq *r)
12061236
{
1237+
struct net_device *dev;
12071238
__be32 ip;
12081239

1240+
dev = arp_req_dev(net, r);
1241+
if (IS_ERR(dev))
1242+
return PTR_ERR(dev);
1243+
12091244
if (r->arp_flags & ATF_PUBL)
12101245
return arp_req_delete_public(net, r, dev);
12111246

12121247
ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
1213-
if (!dev) {
1214-
dev = arp_req_dev(net, r);
1215-
if (IS_ERR(dev))
1216-
return PTR_ERR(dev);
1217-
}
1248+
12181249
return arp_invalidate(dev, ip, true);
12191250
}
12201251

@@ -1224,7 +1255,6 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
12241255

12251256
int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
12261257
{
1227-
struct net_device *dev = NULL;
12281258
struct arpreq r;
12291259
__be32 *netmask;
12301260
int err;
@@ -1258,35 +1288,19 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
12581288
return -EINVAL;
12591289

12601290
rtnl_lock();
1261-
if (r.arp_dev[0]) {
1262-
err = -ENODEV;
1263-
dev = __dev_get_by_name(net, r.arp_dev);
1264-
if (!dev)
1265-
goto out;
1266-
1267-
/* Mmmm... It is wrong... ARPHRD_NETROM==0 */
1268-
if (!r.arp_ha.sa_family)
1269-
r.arp_ha.sa_family = dev->type;
1270-
err = -EINVAL;
1271-
if ((r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type)
1272-
goto out;
1273-
} else if (cmd == SIOCGARP) {
1274-
err = -ENODEV;
1275-
goto out;
1276-
}
12771291

12781292
switch (cmd) {
12791293
case SIOCDARP:
1280-
err = arp_req_delete(net, &r, dev);
1294+
err = arp_req_delete(net, &r);
12811295
break;
12821296
case SIOCSARP:
1283-
err = arp_req_set(net, &r, dev);
1297+
err = arp_req_set(net, &r);
12841298
break;
12851299
case SIOCGARP:
1286-
err = arp_req_get(&r, dev);
1300+
err = arp_req_get(net, &r);
12871301
break;
12881302
}
1289-
out:
1303+
12901304
rtnl_unlock();
12911305
if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r)))
12921306
err = -EFAULT;

0 commit comments

Comments
 (0)