]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ipv4: fib: Don't ignore error route in local/main tables.
authorKuniyuki Iwashima <kuniyu@google.com>
Fri, 19 Jun 2026 21:27:20 +0000 (21:27 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 23 Jun 2026 01:37:36 +0000 (18:37 -0700)
When CONFIG_IP_MULTIPLE_TABLES is enabled but no rule is added,
fib_lookup() performs route lookup directly on two tables.

Since the first lookup does not properly bail out, the result
of an error route in the merged local/main table could be
overwritten by another route in the default table:

  # unshare -n
  # ip link set lo up
  # ip route add 192.168.0.0/24 dev lo table 253
  # ip route add unreachable 192.168.0.0/24
  # ip route get 192.168.0.1
  192.168.0.1 dev lo table default uid 0
      cache <local>

Once a random rule is added, the error route is respected:

  # ip rule add table 0
  # ip rule del table 0
  # ip route get 192.168.0.1
  RTNETLINK answers: No route to host

Let's fix the inconsistent behaviour.

Fixes: f4530fa574df ("ipv4: Avoid overhead when no custom FIB rules are installed.")
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260619212753.3367244-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/ip_fib.h

index a71a9850565079fd9780d5f6ca9fd8a717a326ef..c63a3c4967ae61c07ebb0f6a068f1194260933d0 100644 (file)
@@ -374,7 +374,7 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp,
                             struct fib_result *res, unsigned int flags)
 {
        struct fib_table *tb;
-       int err = -ENETUNREACH;
+       int err = -EAGAIN;
 
        flags |= FIB_LOOKUP_NOREF;
        if (net->ipv4.fib_has_custom_rules)
@@ -388,17 +388,16 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp,
        if (tb)
                err = fib_table_lookup(tb, flp, res, flags);
 
-       if (!err)
+       if (err != -EAGAIN)
                goto out;
 
        tb = rcu_dereference_rtnl(net->ipv4.fib_default);
        if (tb)
                err = fib_table_lookup(tb, flp, res, flags);
 
-out:
        if (err == -EAGAIN)
                err = -ENETUNREACH;
-
+out:
        rcu_read_unlock();
 
        return err;