ipv4: dont create routes on down devices
Eric Dumazet [Wed, 22 Dec 2010 04:39:39 +0000 (04:39 +0000)]
In ip_route_output_slow(), instead of allowing a route to be created on
a not UPed device, report -ENETUNREACH immediately.

# ip tunnel add mode ipip remote 10.16.0.164 local
10.16.0.72 dev eth0
# (Note : tunl1 is down)
# ping -I tunl1 10.1.2.3
PING 10.1.2.3 (10.1.2.3) from 192.168.18.5 tunl1: 56(84) bytes of data.
(nothing)
# ./a.out tunl1
# ip tunnel del tunl1
Message from syslogd@shelby at Dec 22 10:12:08 ...
  kernel: unregister_netdevice: waiting for tunl1 to become free.
Usage count = 3

After patch:
# ping -I tunl1 10.1.2.3
connect: Network is unreachable

Reported-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Reviewed-by: Octavian Purdila <opurdila@ixiacom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

net/ipv4/route.c

index 987bf9a..df948b0 100644 (file)
@@ -2585,9 +2585,10 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
                        goto out;
 
                /* RACE: Check return value of inet_select_addr instead. */
-               if (rcu_dereference(dev_out->ip_ptr) == NULL)
-                       goto out;       /* Wrong error code */
-
+               if (!(dev_out->flags & IFF_UP) || !__in_dev_get_rcu(dev_out)) {
+                       err = -ENETUNREACH;
+                       goto out;
+               }
                if (ipv4_is_local_multicast(oldflp->fl4_dst) ||
                    ipv4_is_lbcast(oldflp->fl4_dst)) {
                        if (!fl.fl4_src)