Skip to content

Commit 5165c48

Browse files
committed
Merge branch 'arp-random-clean-up-and-rcu-conversion-for-ioctl-siocgarp'
Kuniyuki Iwashima says: ==================== arp: Random clean up and RCU conversion for ioctl(SIOCGARP). arp_ioctl() holds rtnl_lock() 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. This series cleans up ioctl() code a bit and extends the RCU section not to take rtnl_lock() and instead use dev_get_by_name_rcu() and netdev_copy_name() for SIOCGARP. v2: https://lore.kernel.org/netdev/20240425170002.68160-1-kuniyu@amazon.com/ v1: https://lore.kernel.org/netdev/20240422194755.4221-1-kuniyu@amazon.com/ ==================== Link: https://lore.kernel.org/r/20240430015813.71143-1-kuniyu@amazon.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 496bc58 + bf4ea58 commit 5165c48

3 files changed

Lines changed: 147 additions & 84 deletions

File tree

include/linux/netdevice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3136,6 +3136,7 @@ struct net_device *netdev_get_by_name(struct net *net, const char *name,
31363136
netdevice_tracker *tracker, gfp_t gfp);
31373137
struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex);
31383138
struct net_device *dev_get_by_napi_id(unsigned int napi_id);
3139+
void netdev_copy_name(struct net_device *dev, char *name);
31393140

31403141
static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,
31413142
unsigned short type,

net/core/dev.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,18 @@ struct net_device *dev_get_by_napi_id(unsigned int napi_id)
940940
}
941941
EXPORT_SYMBOL(dev_get_by_napi_id);
942942

943+
static DEFINE_SEQLOCK(netdev_rename_lock);
944+
945+
void netdev_copy_name(struct net_device *dev, char *name)
946+
{
947+
unsigned int seq;
948+
949+
do {
950+
seq = read_seqbegin(&netdev_rename_lock);
951+
strscpy(name, dev->name, IFNAMSIZ);
952+
} while (read_seqretry(&netdev_rename_lock, seq));
953+
}
954+
943955
/**
944956
* netdev_get_name - get a netdevice name, knowing its ifindex.
945957
* @net: network namespace
@@ -951,7 +963,6 @@ int netdev_get_name(struct net *net, char *name, int ifindex)
951963
struct net_device *dev;
952964
int ret;
953965

954-
down_read(&devnet_rename_sem);
955966
rcu_read_lock();
956967

957968
dev = dev_get_by_index_rcu(net, ifindex);
@@ -960,12 +971,11 @@ int netdev_get_name(struct net *net, char *name, int ifindex)
960971
goto out;
961972
}
962973

963-
strcpy(name, dev->name);
974+
netdev_copy_name(dev, name);
964975

965976
ret = 0;
966977
out:
967978
rcu_read_unlock();
968-
up_read(&devnet_rename_sem);
969979
return ret;
970980
}
971981

@@ -1217,7 +1227,10 @@ int dev_change_name(struct net_device *dev, const char *newname)
12171227

12181228
memcpy(oldname, dev->name, IFNAMSIZ);
12191229

1230+
write_seqlock(&netdev_rename_lock);
12201231
err = dev_get_valid_name(net, dev, newname);
1232+
write_sequnlock(&netdev_rename_lock);
1233+
12211234
if (err < 0) {
12221235
up_write(&devnet_rename_sem);
12231236
return err;
@@ -1257,7 +1270,9 @@ int dev_change_name(struct net_device *dev, const char *newname)
12571270
if (err >= 0) {
12581271
err = ret;
12591272
down_write(&devnet_rename_sem);
1273+
write_seqlock(&netdev_rename_lock);
12601274
memcpy(dev->name, oldname, IFNAMSIZ);
1275+
write_sequnlock(&netdev_rename_lock);
12611276
memcpy(oldname, newname, IFNAMSIZ);
12621277
WRITE_ONCE(dev->name_assign_type, old_assign_type);
12631278
old_assign_type = NET_NAME_RENAMED;
@@ -11403,8 +11418,12 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net,
1140311418
dev_net_set(dev, net);
1140411419
dev->ifindex = new_ifindex;
1140511420

11406-
if (new_name[0]) /* Rename the netdev to prepared name */
11421+
if (new_name[0]) {
11422+
/* Rename the netdev to prepared name */
11423+
write_seqlock(&netdev_rename_lock);
1140711424
strscpy(dev->name, new_name, IFNAMSIZ);
11425+
write_sequnlock(&netdev_rename_lock);
11426+
}
1140811427

1140911428
/* Fixup kobjects */
1141011429
dev_set_uevent_suppress(&dev->dev, 1);

net/ipv4/arp.c

Lines changed: 123 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,55 @@ 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+
bool getarp)
1008+
{
1009+
struct net_device *dev;
1010+
1011+
if (getarp)
1012+
dev = dev_get_by_name_rcu(net, r->arp_dev);
1013+
else
1014+
dev = __dev_get_by_name(net, r->arp_dev);
1015+
if (!dev)
1016+
return ERR_PTR(-ENODEV);
1017+
1018+
/* Mmmm... It is wrong... ARPHRD_NETROM == 0 */
1019+
if (!r->arp_ha.sa_family)
1020+
r->arp_ha.sa_family = dev->type;
1021+
1022+
if ((r->arp_flags & ATF_COM) && r->arp_ha.sa_family != dev->type)
1023+
return ERR_PTR(-EINVAL);
1024+
1025+
return dev;
1026+
}
1027+
1028+
static struct net_device *arp_req_dev(struct net *net, struct arpreq *r)
1029+
{
1030+
struct net_device *dev;
1031+
struct rtable *rt;
1032+
__be32 ip;
1033+
1034+
if (r->arp_dev[0])
1035+
return arp_req_dev_by_name(net, r, false);
1036+
1037+
if (r->arp_flags & ATF_PUBL)
1038+
return NULL;
1039+
1040+
ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
1041+
1042+
rt = ip_route_output(net, ip, 0, 0, 0, RT_SCOPE_LINK);
1043+
if (IS_ERR(rt))
1044+
return ERR_CAST(rt);
1045+
1046+
dev = rt->dst.dev;
1047+
ip_rt_put(rt);
1048+
1049+
if (!dev)
1050+
return ERR_PTR(-EINVAL);
1051+
1052+
return dev;
1053+
}
1054+
10061055
/*
10071056
* Set (create) an ARP cache entry.
10081057
*/
@@ -1023,18 +1072,17 @@ static int arp_req_set_proxy(struct net *net, struct net_device *dev, int on)
10231072
static int arp_req_set_public(struct net *net, struct arpreq *r,
10241073
struct net_device *dev)
10251074
{
1026-
__be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
10271075
__be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;
10281076

1029-
if (mask && mask != htonl(0xFFFFFFFF))
1030-
return -EINVAL;
10311077
if (!dev && (r->arp_flags & ATF_COM)) {
10321078
dev = dev_getbyhwaddr_rcu(net, r->arp_ha.sa_family,
10331079
r->arp_ha.sa_data);
10341080
if (!dev)
10351081
return -ENODEV;
10361082
}
10371083
if (mask) {
1084+
__be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
1085+
10381086
if (!pneigh_lookup(&arp_tbl, net, &ip, dev, 1))
10391087
return -ENOBUFS;
10401088
return 0;
@@ -1043,30 +1091,20 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
10431091
return arp_req_set_proxy(net, dev, 1);
10441092
}
10451093

1046-
static int arp_req_set(struct net *net, struct arpreq *r,
1047-
struct net_device *dev)
1094+
static int arp_req_set(struct net *net, struct arpreq *r)
10481095
{
1049-
__be32 ip;
10501096
struct neighbour *neigh;
1097+
struct net_device *dev;
1098+
__be32 ip;
10511099
int err;
10521100

1101+
dev = arp_req_dev(net, r);
1102+
if (IS_ERR(dev))
1103+
return PTR_ERR(dev);
1104+
10531105
if (r->arp_flags & ATF_PUBL)
10541106
return arp_req_set_public(net, r, dev);
10551107

1056-
ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
1057-
if (r->arp_flags & ATF_PERM)
1058-
r->arp_flags |= ATF_COM;
1059-
if (!dev) {
1060-
struct rtable *rt = ip_route_output(net, ip, 0, 0, 0,
1061-
RT_SCOPE_LINK);
1062-
1063-
if (IS_ERR(rt))
1064-
return PTR_ERR(rt);
1065-
dev = rt->dst.dev;
1066-
ip_rt_put(rt);
1067-
if (!dev)
1068-
return -EINVAL;
1069-
}
10701108
switch (dev->type) {
10711109
#if IS_ENABLED(CONFIG_FDDI)
10721110
case ARPHRD_FDDI:
@@ -1088,12 +1126,18 @@ static int arp_req_set(struct net *net, struct arpreq *r,
10881126
break;
10891127
}
10901128

1129+
ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
1130+
10911131
neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev);
10921132
err = PTR_ERR(neigh);
10931133
if (!IS_ERR(neigh)) {
10941134
unsigned int state = NUD_STALE;
1095-
if (r->arp_flags & ATF_PERM)
1135+
1136+
if (r->arp_flags & ATF_PERM) {
1137+
r->arp_flags |= ATF_COM;
10961138
state = NUD_PERMANENT;
1139+
}
1140+
10971141
err = neigh_update(neigh, (r->arp_flags & ATF_COM) ?
10981142
r->arp_ha.sa_data : NULL, state,
10991143
NEIGH_UPDATE_F_OVERRIDE |
@@ -1117,27 +1161,40 @@ static unsigned int arp_state_to_flags(struct neighbour *neigh)
11171161
* Get an ARP cache entry.
11181162
*/
11191163

1120-
static int arp_req_get(struct arpreq *r, struct net_device *dev)
1164+
static int arp_req_get(struct net *net, struct arpreq *r)
11211165
{
11221166
__be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
11231167
struct neighbour *neigh;
1124-
int err = -ENXIO;
1168+
struct net_device *dev;
1169+
1170+
if (!r->arp_dev[0])
1171+
return -ENODEV;
1172+
1173+
dev = arp_req_dev_by_name(net, r, true);
1174+
if (IS_ERR(dev))
1175+
return PTR_ERR(dev);
11251176

11261177
neigh = neigh_lookup(&arp_tbl, &ip, dev);
1127-
if (neigh) {
1128-
if (!(READ_ONCE(neigh->nud_state) & NUD_NOARP)) {
1129-
read_lock_bh(&neigh->lock);
1130-
memcpy(r->arp_ha.sa_data, neigh->ha,
1131-
min(dev->addr_len, sizeof(r->arp_ha.sa_data_min)));
1132-
r->arp_flags = arp_state_to_flags(neigh);
1133-
read_unlock_bh(&neigh->lock);
1134-
r->arp_ha.sa_family = dev->type;
1135-
strscpy(r->arp_dev, dev->name, sizeof(r->arp_dev));
1136-
err = 0;
1137-
}
1178+
if (!neigh)
1179+
return -ENXIO;
1180+
1181+
if (READ_ONCE(neigh->nud_state) & NUD_NOARP) {
11381182
neigh_release(neigh);
1183+
return -ENXIO;
11391184
}
1140-
return err;
1185+
1186+
read_lock_bh(&neigh->lock);
1187+
memcpy(r->arp_ha.sa_data, neigh->ha,
1188+
min(dev->addr_len, sizeof(r->arp_ha.sa_data_min)));
1189+
r->arp_flags = arp_state_to_flags(neigh);
1190+
read_unlock_bh(&neigh->lock);
1191+
1192+
neigh_release(neigh);
1193+
1194+
r->arp_ha.sa_family = dev->type;
1195+
netdev_copy_name(dev, r->arp_dev);
1196+
1197+
return 0;
11411198
}
11421199

11431200
int arp_invalidate(struct net_device *dev, __be32 ip, bool force)
@@ -1168,37 +1225,31 @@ int arp_invalidate(struct net_device *dev, __be32 ip, bool force)
11681225
static int arp_req_delete_public(struct net *net, struct arpreq *r,
11691226
struct net_device *dev)
11701227
{
1171-
__be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
11721228
__be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;
11731229

1174-
if (mask == htonl(0xFFFFFFFF))
1175-
return pneigh_delete(&arp_tbl, net, &ip, dev);
1230+
if (mask) {
1231+
__be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
11761232

1177-
if (mask)
1178-
return -EINVAL;
1233+
return pneigh_delete(&arp_tbl, net, &ip, dev);
1234+
}
11791235

11801236
return arp_req_set_proxy(net, dev, 0);
11811237
}
11821238

1183-
static int arp_req_delete(struct net *net, struct arpreq *r,
1184-
struct net_device *dev)
1239+
static int arp_req_delete(struct net *net, struct arpreq *r)
11851240
{
1241+
struct net_device *dev;
11861242
__be32 ip;
11871243

1244+
dev = arp_req_dev(net, r);
1245+
if (IS_ERR(dev))
1246+
return PTR_ERR(dev);
1247+
11881248
if (r->arp_flags & ATF_PUBL)
11891249
return arp_req_delete_public(net, r, dev);
11901250

11911251
ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
1192-
if (!dev) {
1193-
struct rtable *rt = ip_route_output(net, ip, 0, 0, 0,
1194-
RT_SCOPE_LINK);
1195-
if (IS_ERR(rt))
1196-
return PTR_ERR(rt);
1197-
dev = rt->dst.dev;
1198-
ip_rt_put(rt);
1199-
if (!dev)
1200-
return -EINVAL;
1201-
}
1252+
12021253
return arp_invalidate(dev, ip, true);
12031254
}
12041255

@@ -1208,9 +1259,9 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
12081259

12091260
int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
12101261
{
1211-
int err;
12121262
struct arpreq r;
1213-
struct net_device *dev = NULL;
1263+
__be32 *netmask;
1264+
int err;
12141265

12151266
switch (cmd) {
12161267
case SIOCDARP:
@@ -1233,42 +1284,34 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
12331284
if (!(r.arp_flags & ATF_PUBL) &&
12341285
(r.arp_flags & (ATF_NETMASK | ATF_DONTPUB)))
12351286
return -EINVAL;
1287+
1288+
netmask = &((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr;
12361289
if (!(r.arp_flags & ATF_NETMASK))
1237-
((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
1238-
htonl(0xFFFFFFFFUL);
1239-
rtnl_lock();
1240-
if (r.arp_dev[0]) {
1241-
err = -ENODEV;
1242-
dev = __dev_get_by_name(net, r.arp_dev);
1243-
if (!dev)
1244-
goto out;
1245-
1246-
/* Mmmm... It is wrong... ARPHRD_NETROM==0 */
1247-
if (!r.arp_ha.sa_family)
1248-
r.arp_ha.sa_family = dev->type;
1249-
err = -EINVAL;
1250-
if ((r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type)
1251-
goto out;
1252-
} else if (cmd == SIOCGARP) {
1253-
err = -ENODEV;
1254-
goto out;
1255-
}
1290+
*netmask = htonl(0xFFFFFFFFUL);
1291+
else if (*netmask && *netmask != htonl(0xFFFFFFFFUL))
1292+
return -EINVAL;
12561293

12571294
switch (cmd) {
12581295
case SIOCDARP:
1259-
err = arp_req_delete(net, &r, dev);
1296+
rtnl_lock();
1297+
err = arp_req_delete(net, &r);
1298+
rtnl_unlock();
12601299
break;
12611300
case SIOCSARP:
1262-
err = arp_req_set(net, &r, dev);
1301+
rtnl_lock();
1302+
err = arp_req_set(net, &r);
1303+
rtnl_unlock();
12631304
break;
12641305
case SIOCGARP:
1265-
err = arp_req_get(&r, dev);
1306+
rcu_read_lock();
1307+
err = arp_req_get(net, &r);
1308+
rcu_read_unlock();
1309+
1310+
if (!err && copy_to_user(arg, &r, sizeof(r)))
1311+
err = -EFAULT;
12661312
break;
12671313
}
1268-
out:
1269-
rtnl_unlock();
1270-
if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r)))
1271-
err = -EFAULT;
1314+
12721315
return err;
12731316
}
12741317

0 commit comments

Comments
 (0)