]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
blackhole_netdev: fix syzkaller reported issue
authorMahesh Bandewar <maheshb@google.com>
Sat, 12 Oct 2019 01:14:55 +0000 (18:14 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 15 Oct 2019 17:35:23 +0000 (10:35 -0700)
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>
net/ipv6/addrconf.c
net/ipv6/route.c

index 34ccef18b40e60e283a63c18102fef8b927cbfaf..4c87594d1389d6e0927cbfa0ff7b5e631c331e84 100644 (file)
@@ -6996,7 +6996,7 @@ static struct rtnl_af_ops inet6_ops __read_mostly = {
 
 int __init addrconf_init(void)
 {
-       struct inet6_dev *idev;
+       struct inet6_dev *idev, *bdev;
        int i, err;
 
        err = ipv6_addr_label_init();
@@ -7036,10 +7036,14 @@ int __init addrconf_init(void)
         */
        rtnl_lock();
        idev = ipv6_add_dev(init_net.loopback_dev);
+       bdev = ipv6_add_dev(blackhole_netdev);
        rtnl_unlock();
        if (IS_ERR(idev)) {
                err = PTR_ERR(idev);
                goto errlo;
+       } else if (IS_ERR(bdev)) {
+               err = PTR_ERR(bdev);
+               goto errlo;
        }
 
        ip6_route_init_special_entries();
@@ -7124,6 +7128,7 @@ void addrconf_cleanup(void)
                addrconf_ifdown(dev, 1);
        }
        addrconf_ifdown(init_net.loopback_dev, 2);
+       addrconf_ifdown(blackhole_netdev, 2);
 
        /*
         *      Check hash table.
index a63ff85fe14198fc23a5cbc7abcd107df5df00c8..7421207288690078f021117980a28fd01c3a4255 100644 (file)
@@ -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);
                }
        }