提交 394ec9b5 编写于 作者: I Ido Schimmel 提交者: Yongqiang Liu

ipv4: Invalidate neighbour for broadcast address upon address addition

stable inclusion
from stable-4.19.238
commit 75517bd7e4afad5a800b4d14f80aa7e6f73a9681
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I5A6BA
CVE: NA

--------------------------------

[ Upstream commit 0c51e12e ]

In case user space sends a packet destined to a broadcast address when a
matching broadcast route is not configured, the kernel will create a
unicast neighbour entry that will never be resolved [1].

When the broadcast route is configured, the unicast neighbour entry will
not be invalidated and continue to linger, resulting in packets being
dropped.

Solve this by invalidating unresolved neighbour entries for broadcast
addresses after routes for these addresses are internally configured by
the kernel. This allows the kernel to create a broadcast neighbour entry
following the next route lookup.

Another possible solution that is more generic but also more complex is
to have the ARP code register a listener to the FIB notification chain
and invalidate matching neighbour entries upon the addition of broadcast
routes.

It is also possible to wave off the issue as a user space problem, but
it seems a bit excessive to expect user space to be that intimately
familiar with the inner workings of the FIB/neighbour kernel code.

[1] https://lore.kernel.org/netdev/55a04a8f-56f3-f73c-2aea-2195923f09d1@huawei.com/Reported-by: NWang Hai <wanghai38@huawei.com>
Signed-off-by: NIdo Schimmel <idosch@nvidia.com>
Tested-by: NWang Hai <wanghai38@huawei.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
Signed-off-by: NSasha Levin <sashal@kernel.org>
Signed-off-by: NYongqiang Liu <liuyongqiang13@huawei.com>
上级 d934ba36
...@@ -71,6 +71,7 @@ void arp_send(int type, int ptype, __be32 dest_ip, ...@@ -71,6 +71,7 @@ void arp_send(int type, int ptype, __be32 dest_ip,
const unsigned char *src_hw, const unsigned char *th); const unsigned char *src_hw, const unsigned char *th);
int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir); int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir);
void arp_ifdown(struct net_device *dev); void arp_ifdown(struct net_device *dev);
int arp_invalidate(struct net_device *dev, __be32 ip, bool force);
struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
struct net_device *dev, __be32 src_ip, struct net_device *dev, __be32 src_ip,
......
...@@ -1114,13 +1114,18 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev) ...@@ -1114,13 +1114,18 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev)
return err; return err;
} }
static int arp_invalidate(struct net_device *dev, __be32 ip) int arp_invalidate(struct net_device *dev, __be32 ip, bool force)
{ {
struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev); struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev);
int err = -ENXIO; int err = -ENXIO;
struct neigh_table *tbl = &arp_tbl; struct neigh_table *tbl = &arp_tbl;
if (neigh) { if (neigh) {
if ((neigh->nud_state & NUD_VALID) && !force) {
neigh_release(neigh);
return 0;
}
if (neigh->nud_state & ~NUD_NOARP) if (neigh->nud_state & ~NUD_NOARP)
err = neigh_update(neigh, NULL, NUD_FAILED, err = neigh_update(neigh, NULL, NUD_FAILED,
NEIGH_UPDATE_F_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE|
...@@ -1167,7 +1172,7 @@ static int arp_req_delete(struct net *net, struct arpreq *r, ...@@ -1167,7 +1172,7 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
if (!dev) if (!dev)
return -EINVAL; return -EINVAL;
} }
return arp_invalidate(dev, ip); return arp_invalidate(dev, ip, true);
} }
/* /*
......
...@@ -917,9 +917,11 @@ void fib_add_ifaddr(struct in_ifaddr *ifa) ...@@ -917,9 +917,11 @@ void fib_add_ifaddr(struct in_ifaddr *ifa)
return; return;
/* Add broadcast address, if it is explicitly assigned. */ /* Add broadcast address, if it is explicitly assigned. */
if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF)) if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF)) {
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32,
prim, 0); prim, 0);
arp_invalidate(dev, ifa->ifa_broadcast, false);
}
if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) && if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) &&
(prefix != addr || ifa->ifa_prefixlen < 32)) { (prefix != addr || ifa->ifa_prefixlen < 32)) {
...@@ -935,6 +937,7 @@ void fib_add_ifaddr(struct in_ifaddr *ifa) ...@@ -935,6 +937,7 @@ void fib_add_ifaddr(struct in_ifaddr *ifa)
prim, 0); prim, 0);
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask, fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask,
32, prim, 0); 32, prim, 0);
arp_invalidate(dev, prefix | ~mask, false);
} }
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册