Skip to content

Commit 0592367

Browse files
q2venkuba-moo
authored andcommitted
arp: Validate netmask earlier for SIOCDARP and SIOCSARP in arp_ioctl().
When ioctl(SIOCDARP/SIOCSARP) is issued with ATF_PUBL, r.arp_netmask must be 0.0.0.0 or 255.255.255.255. Currently, the netmask is validated in arp_req_delete_public() or arp_req_set_public() under rtnl_lock(). We have ATF_NETMASK test in arp_ioctl() before holding rtnl_lock(), so let's move the netmask validation there. Signed-off-by: Kuniyuki Iwashima <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 42033d0 commit 0592367

File tree

1 file changed

+15
-12
lines changed

1 file changed

+15
-12
lines changed

net/ipv4/arp.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,18 +1023,17 @@ static int arp_req_set_proxy(struct net *net, struct net_device *dev, int on)
10231023
static int arp_req_set_public(struct net *net, struct arpreq *r,
10241024
struct net_device *dev)
10251025
{
1026-
__be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
10271026
__be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;
10281027

1029-
if (mask && mask != htonl(0xFFFFFFFF))
1030-
return -EINVAL;
10311028
if (!dev && (r->arp_flags & ATF_COM)) {
10321029
dev = dev_getbyhwaddr_rcu(net, r->arp_ha.sa_family,
10331030
r->arp_ha.sa_data);
10341031
if (!dev)
10351032
return -ENODEV;
10361033
}
10371034
if (mask) {
1035+
__be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
1036+
10381037
if (!pneigh_lookup(&arp_tbl, net, &ip, dev, 1))
10391038
return -ENOBUFS;
10401039
return 0;
@@ -1171,14 +1170,13 @@ int arp_invalidate(struct net_device *dev, __be32 ip, bool force)
11711170
static int arp_req_delete_public(struct net *net, struct arpreq *r,
11721171
struct net_device *dev)
11731172
{
1174-
__be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
11751173
__be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;
11761174

1177-
if (mask == htonl(0xFFFFFFFF))
1178-
return pneigh_delete(&arp_tbl, net, &ip, dev);
1175+
if (mask) {
1176+
__be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
11791177

1180-
if (mask)
1181-
return -EINVAL;
1178+
return pneigh_delete(&arp_tbl, net, &ip, dev);
1179+
}
11821180

11831181
return arp_req_set_proxy(net, dev, 0);
11841182
}
@@ -1211,9 +1209,10 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
12111209

12121210
int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
12131211
{
1214-
int err;
1215-
struct arpreq r;
12161212
struct net_device *dev = NULL;
1213+
struct arpreq r;
1214+
__be32 *netmask;
1215+
int err;
12171216

12181217
switch (cmd) {
12191218
case SIOCDARP:
@@ -1236,9 +1235,13 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
12361235
if (!(r.arp_flags & ATF_PUBL) &&
12371236
(r.arp_flags & (ATF_NETMASK | ATF_DONTPUB)))
12381237
return -EINVAL;
1238+
1239+
netmask = &((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr;
12391240
if (!(r.arp_flags & ATF_NETMASK))
1240-
((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
1241-
htonl(0xFFFFFFFFUL);
1241+
*netmask = htonl(0xFFFFFFFFUL);
1242+
else if (*netmask && *netmask != htonl(0xFFFFFFFFUL))
1243+
return -EINVAL;
1244+
12421245
rtnl_lock();
12431246
if (r.arp_dev[0]) {
12441247
err = -ENODEV;

0 commit comments

Comments
 (0)