aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
authorMahesh Bandewar <maheshb@google.com>2019-10-11 18:14:55 -0700
committerDavid S. Miller <davem@davemloft.net>2019-10-15 10:35:23 -0700
commitb0818f80c8c1bc215bba276bd61c216014fab23b (patch)
tree4ca7931e6ae9d3e2d3d115d01b0fda824a9ca97e /net/ipv6/route.c
parentMerge tag 'wireless-drivers-for-davem-2019-10-15' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers (diff)
downloadlinux-dev-b0818f80c8c1bc215bba276bd61c216014fab23b.tar.xz
linux-dev-b0818f80c8c1bc215bba276bd61c216014fab23b.zip
blackhole_netdev: fix syzkaller reported issue
While invalidating the dst, we assign backhole_netdev instead of loopback device. However, this device does not have idev pointer and hence no ip6_ptr even if IPv6 is enabled. Possibly this has triggered the syzbot reported crash. The syzbot report does not have reproducer, however, this is the only device that doesn't have matching idev created. Crash instruction is : static inline bool ip6_ignore_linkdown(const struct net_device *dev) { const struct inet6_dev *idev = __in6_dev_get(dev); return !!idev->cnf.ignore_routes_with_linkdown; <= crash } Also ipv6 always assumes presence of idev and never checks for it being NULL (as does the above referenced code). So adding a idev for the blackhole_netdev to avoid this class of crashes in the future. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to '')
-rw-r--r--net/ipv6/route.c15
1 files changed, 6 insertions, 9 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index a63ff85fe141..742120728869 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -155,10 +155,9 @@ void rt6_uncached_list_del(struct rt6_info *rt)
static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
{
- struct net_device *loopback_dev = net->loopback_dev;
int cpu;
- if (dev == loopback_dev)
+ if (dev == net->loopback_dev)
return;
for_each_possible_cpu(cpu) {
@@ -171,7 +170,7 @@ static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
struct net_device *rt_dev = rt->dst.dev;
if (rt_idev->dev == dev) {
- rt->rt6i_idev = in6_dev_get(loopback_dev);
+ rt->rt6i_idev = in6_dev_get(blackhole_netdev);
in6_dev_put(rt_idev);
}
@@ -386,13 +385,11 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
{
struct rt6_info *rt = (struct rt6_info *)dst;
struct inet6_dev *idev = rt->rt6i_idev;
- struct net_device *loopback_dev =
- dev_net(dev)->loopback_dev;
- if (idev && idev->dev != loopback_dev) {
- struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
- if (loopback_idev) {
- rt->rt6i_idev = loopback_idev;
+ if (idev && idev->dev != dev_net(dev)->loopback_dev) {
+ struct inet6_dev *ibdev = in6_dev_get(blackhole_netdev);
+ if (ibdev) {
+ rt->rt6i_idev = ibdev;
in6_dev_put(idev);
}
}