Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+147 -84
+1
include/linux/netdevice.h
··· 3136 3136 netdevice_tracker *tracker, gfp_t gfp); 3137 3137 struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex); 3138 3138 struct net_device *dev_get_by_napi_id(unsigned int napi_id); 3139 + void netdev_copy_name(struct net_device *dev, char *name); 3139 3140 3140 3141 static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, 3141 3142 unsigned short type,
+23 -4
net/core/dev.c
··· 940 940 } 941 941 EXPORT_SYMBOL(dev_get_by_napi_id); 942 942 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 + 943 955 /** 944 956 * netdev_get_name - get a netdevice name, knowing its ifindex. 945 957 * @net: network namespace ··· 963 951 struct net_device *dev; 964 952 int ret; 965 953 966 - down_read(&devnet_rename_sem); 967 954 rcu_read_lock(); 968 955 969 956 dev = dev_get_by_index_rcu(net, ifindex); ··· 971 960 goto out; 972 961 } 973 962 974 - strcpy(name, dev->name); 963 + netdev_copy_name(dev, name); 975 964 976 965 ret = 0; 977 966 out: 978 967 rcu_read_unlock(); 979 - up_read(&devnet_rename_sem); 980 968 return ret; 981 969 } 982 970 ··· 1227 1217 1228 1218 memcpy(oldname, dev->name, IFNAMSIZ); 1229 1219 1220 + write_seqlock(&netdev_rename_lock); 1230 1221 err = dev_get_valid_name(net, dev, newname); 1222 + write_sequnlock(&netdev_rename_lock); 1223 + 1231 1224 if (err < 0) { 1232 1225 up_write(&devnet_rename_sem); 1233 1226 return err; ··· 1270 1257 if (err >= 0) { 1271 1258 err = ret; 1272 1259 down_write(&devnet_rename_sem); 1260 + write_seqlock(&netdev_rename_lock); 1273 1261 memcpy(dev->name, oldname, IFNAMSIZ); 1262 + write_sequnlock(&netdev_rename_lock); 1274 1263 memcpy(oldname, newname, IFNAMSIZ); 1275 1264 WRITE_ONCE(dev->name_assign_type, old_assign_type); 1276 1265 old_assign_type = NET_NAME_RENAMED; ··· 11418 11403 dev_net_set(dev, net); 11419 11404 dev->ifindex = new_ifindex; 11420 11405 11421 - if (new_name[0]) /* Rename the netdev to prepared name */ 11406 + if (new_name[0]) { 11407 + /* Rename the netdev to prepared name */ 11408 + write_seqlock(&netdev_rename_lock); 11422 11409 strscpy(dev->name, new_name, IFNAMSIZ); 11410 + write_sequnlock(&netdev_rename_lock); 11411 + } 11423 11412 11424 11413 /* Fixup kobjects */ 11425 11414 dev_set_uevent_suppress(&dev->dev, 1);
+123 -80
net/ipv4/arp.c
··· 1003 1003 * User level interface (ioctl) 1004 1004 */ 1005 1005 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 + 1006 1055 /* 1007 1056 * Set (create) an ARP cache entry. 1008 1057 */ ··· 1072 1023 static int arp_req_set_public(struct net *net, struct arpreq *r, 1073 1024 struct net_device *dev) 1074 1025 { 1075 - __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; 1076 1026 __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; 1077 1027 1078 - if (mask && mask != htonl(0xFFFFFFFF)) 1079 - return -EINVAL; 1080 1028 if (!dev && (r->arp_flags & ATF_COM)) { 1081 1029 dev = dev_getbyhwaddr_rcu(net, r->arp_ha.sa_family, 1082 1030 r->arp_ha.sa_data); ··· 1081 1035 return -ENODEV; 1082 1036 } 1083 1037 if (mask) { 1038 + __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; 1039 + 1084 1040 if (!pneigh_lookup(&arp_tbl, net, &ip, dev, 1)) 1085 1041 return -ENOBUFS; 1086 1042 return 0; ··· 1091 1043 return arp_req_set_proxy(net, dev, 1); 1092 1044 } 1093 1045 1094 - static int arp_req_set(struct net *net, struct arpreq *r, 1095 - struct net_device *dev) 1046 + static int arp_req_set(struct net *net, struct arpreq *r) 1096 1047 { 1097 - __be32 ip; 1098 1048 struct neighbour *neigh; 1049 + struct net_device *dev; 1050 + __be32 ip; 1099 1051 int err; 1052 + 1053 + dev = arp_req_dev(net, r); 1054 + if (IS_ERR(dev)) 1055 + return PTR_ERR(dev); 1100 1056 1101 1057 if (r->arp_flags & ATF_PUBL) 1102 1058 return arp_req_set_public(net, r, dev); 1103 1059 1104 - ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; 1105 - if (r->arp_flags & ATF_PERM) 1106 - r->arp_flags |= ATF_COM; 1107 - if (!dev) { 1108 - struct rtable *rt = ip_route_output(net, ip, 0, 0, 0, 1109 - RT_SCOPE_LINK); 1110 - 1111 - if (IS_ERR(rt)) 1112 - return PTR_ERR(rt); 1113 - dev = rt->dst.dev; 1114 - ip_rt_put(rt); 1115 - if (!dev) 1116 - return -EINVAL; 1117 - } 1118 1060 switch (dev->type) { 1119 1061 #if IS_ENABLED(CONFIG_FDDI) 1120 1062 case ARPHRD_FDDI: ··· 1126 1088 break; 1127 1089 } 1128 1090 1091 + ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; 1092 + 1129 1093 neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev); 1130 1094 err = PTR_ERR(neigh); 1131 1095 if (!IS_ERR(neigh)) { 1132 1096 unsigned int state = NUD_STALE; 1133 - if (r->arp_flags & ATF_PERM) 1097 + 1098 + if (r->arp_flags & ATF_PERM) { 1099 + r->arp_flags |= ATF_COM; 1134 1100 state = NUD_PERMANENT; 1101 + } 1102 + 1135 1103 err = neigh_update(neigh, (r->arp_flags & ATF_COM) ? 1136 1104 r->arp_ha.sa_data : NULL, state, 1137 1105 NEIGH_UPDATE_F_OVERRIDE | ··· 1161 1117 * Get an ARP cache entry. 1162 1118 */ 1163 1119 1164 - static int arp_req_get(struct arpreq *r, struct net_device *dev) 1120 + static int arp_req_get(struct net *net, struct arpreq *r) 1165 1121 { 1166 1122 __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; 1167 1123 struct neighbour *neigh; 1168 - int err = -ENXIO; 1124 + struct net_device *dev; 1125 + 1126 + if (!r->arp_dev[0]) 1127 + return -ENODEV; 1128 + 1129 + dev = arp_req_dev_by_name(net, r, true); 1130 + if (IS_ERR(dev)) 1131 + return PTR_ERR(dev); 1169 1132 1170 1133 neigh = neigh_lookup(&arp_tbl, &ip, dev); 1171 - if (neigh) { 1172 - if (!(READ_ONCE(neigh->nud_state) & NUD_NOARP)) { 1173 - read_lock_bh(&neigh->lock); 1174 - memcpy(r->arp_ha.sa_data, neigh->ha, 1175 - min(dev->addr_len, sizeof(r->arp_ha.sa_data_min))); 1176 - r->arp_flags = arp_state_to_flags(neigh); 1177 - read_unlock_bh(&neigh->lock); 1178 - r->arp_ha.sa_family = dev->type; 1179 - strscpy(r->arp_dev, dev->name, sizeof(r->arp_dev)); 1180 - err = 0; 1181 - } 1134 + if (!neigh) 1135 + return -ENXIO; 1136 + 1137 + if (READ_ONCE(neigh->nud_state) & NUD_NOARP) { 1182 1138 neigh_release(neigh); 1139 + return -ENXIO; 1183 1140 } 1184 - return err; 1141 + 1142 + read_lock_bh(&neigh->lock); 1143 + memcpy(r->arp_ha.sa_data, neigh->ha, 1144 + min(dev->addr_len, sizeof(r->arp_ha.sa_data_min))); 1145 + r->arp_flags = arp_state_to_flags(neigh); 1146 + read_unlock_bh(&neigh->lock); 1147 + 1148 + neigh_release(neigh); 1149 + 1150 + r->arp_ha.sa_family = dev->type; 1151 + netdev_copy_name(dev, r->arp_dev); 1152 + 1153 + return 0; 1185 1154 } 1186 1155 1187 1156 int arp_invalidate(struct net_device *dev, __be32 ip, bool force) ··· 1225 1168 static int arp_req_delete_public(struct net *net, struct arpreq *r, 1226 1169 struct net_device *dev) 1227 1170 { 1228 - __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; 1229 1171 __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; 1230 1172 1231 - if (mask == htonl(0xFFFFFFFF)) 1232 - return pneigh_delete(&arp_tbl, net, &ip, dev); 1173 + if (mask) { 1174 + __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; 1233 1175 1234 - if (mask) 1235 - return -EINVAL; 1176 + return pneigh_delete(&arp_tbl, net, &ip, dev); 1177 + } 1236 1178 1237 1179 return arp_req_set_proxy(net, dev, 0); 1238 1180 } 1239 1181 1240 - static int arp_req_delete(struct net *net, struct arpreq *r, 1241 - struct net_device *dev) 1182 + static int arp_req_delete(struct net *net, struct arpreq *r) 1242 1183 { 1184 + struct net_device *dev; 1243 1185 __be32 ip; 1186 + 1187 + dev = arp_req_dev(net, r); 1188 + if (IS_ERR(dev)) 1189 + return PTR_ERR(dev); 1244 1190 1245 1191 if (r->arp_flags & ATF_PUBL) 1246 1192 return arp_req_delete_public(net, r, dev); 1247 1193 1248 1194 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; 1249 - if (!dev) { 1250 - struct rtable *rt = ip_route_output(net, ip, 0, 0, 0, 1251 - RT_SCOPE_LINK); 1252 - if (IS_ERR(rt)) 1253 - return PTR_ERR(rt); 1254 - dev = rt->dst.dev; 1255 - ip_rt_put(rt); 1256 - if (!dev) 1257 - return -EINVAL; 1258 - } 1195 + 1259 1196 return arp_invalidate(dev, ip, true); 1260 1197 } 1261 1198 ··· 1259 1208 1260 1209 int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg) 1261 1210 { 1262 - int err; 1263 1211 struct arpreq r; 1264 - struct net_device *dev = NULL; 1212 + __be32 *netmask; 1213 + int err; 1265 1214 1266 1215 switch (cmd) { 1267 1216 case SIOCDARP: ··· 1284 1233 if (!(r.arp_flags & ATF_PUBL) && 1285 1234 (r.arp_flags & (ATF_NETMASK | ATF_DONTPUB))) 1286 1235 return -EINVAL; 1287 - if (!(r.arp_flags & ATF_NETMASK)) 1288 - ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr = 1289 - htonl(0xFFFFFFFFUL); 1290 - rtnl_lock(); 1291 - if (r.arp_dev[0]) { 1292 - err = -ENODEV; 1293 - dev = __dev_get_by_name(net, r.arp_dev); 1294 - if (!dev) 1295 - goto out; 1296 1236 1297 - /* Mmmm... It is wrong... ARPHRD_NETROM==0 */ 1298 - if (!r.arp_ha.sa_family) 1299 - r.arp_ha.sa_family = dev->type; 1300 - err = -EINVAL; 1301 - if ((r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type) 1302 - goto out; 1303 - } else if (cmd == SIOCGARP) { 1304 - err = -ENODEV; 1305 - goto out; 1306 - } 1237 + netmask = &((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr; 1238 + if (!(r.arp_flags & ATF_NETMASK)) 1239 + *netmask = htonl(0xFFFFFFFFUL); 1240 + else if (*netmask && *netmask != htonl(0xFFFFFFFFUL)) 1241 + return -EINVAL; 1307 1242 1308 1243 switch (cmd) { 1309 1244 case SIOCDARP: 1310 - err = arp_req_delete(net, &r, dev); 1245 + rtnl_lock(); 1246 + err = arp_req_delete(net, &r); 1247 + rtnl_unlock(); 1311 1248 break; 1312 1249 case SIOCSARP: 1313 - err = arp_req_set(net, &r, dev); 1250 + rtnl_lock(); 1251 + err = arp_req_set(net, &r); 1252 + rtnl_unlock(); 1314 1253 break; 1315 1254 case SIOCGARP: 1316 - err = arp_req_get(&r, dev); 1255 + rcu_read_lock(); 1256 + err = arp_req_get(net, &r); 1257 + rcu_read_unlock(); 1258 + 1259 + if (!err && copy_to_user(arg, &r, sizeof(r))) 1260 + err = -EFAULT; 1317 1261 break; 1318 1262 } 1319 - out: 1320 - rtnl_unlock(); 1321 - if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r))) 1322 - err = -EFAULT; 1263 + 1323 1264 return err; 1324 1265 } 1325 1266