* [PATCH net v2 1/4] ipv4: add FIB_LOOKUP_REPORT_MISS
[not found] <20261110061536.10811-1-liamsmith827@grapheneos.org>
@ 2026-11-10 6:15 ` liamsmith827
2026-11-10 6:15 ` [PATCH net v2 2/4] ipv4: restrict on-link fallback to lookup misses liamsmith827
2026-11-10 6:15 ` [PATCH net v2 3/4] selftests: net: test restricted on-link fallback liamsmith827
2 siblings, 0 replies; 4+ messages in thread
From: liamsmith827 @ 2026-11-10 6:15 UTC (permalink / raw)
To: netdev
Cc: David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
linux-kselftest, linux-kernel, liamsmith827, stable
From: liamsmith827 <liamsmith827@proton.me>
IPv4 FIB lookup maps a routing miss to -ENETUNREACH, which is also
returned when an unreachable rule is encountered. This flag prevents the
mapping, returning -ESRCH instead.
Cc: stable@vger.kernel.org
Signed-off-by: liamsmith827 <liamsmith827@proton.me>
---
include/net/fib_rules.h | 5 +++++
include/net/ip_fib.h | 6 +++---
net/ipv4/fib_rules.c | 2 +-
3 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index c6b94790fa81..bcb6809dbd10 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -59,6 +59,11 @@ struct fib_lookup_arg {
int flags;
#define FIB_LOOKUP_NOREF 1
#define FIB_LOOKUP_IGNORE_LINKSTATE 2
+/* Return -ESRCH instead of mapping it to -ENETUNREACH. Only applies to IPv4
+ * lookups. When used with FIB_LOOKUP_NOREF, -ESRCH indicates the lookup
+ * exhausted all rules and tables without finding a usable route.
+ */
+#define FIB_LOOKUP_REPORT_MISS 4
};
struct fib_rules_ops {
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 92f4eb8b86d7..d0b4f261585a 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -318,7 +318,7 @@ static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
struct fib_result *res, unsigned int flags)
{
struct fib_table *tb;
- int err = -ENETUNREACH;
+ int err = -EAGAIN;
rcu_read_lock();
@@ -327,7 +327,7 @@ static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
err = fib_table_lookup(tb, flp, res, flags | FIB_LOOKUP_NOREF);
if (err == -EAGAIN)
- err = -ENETUNREACH;
+ err = (flags & FIB_LOOKUP_REPORT_MISS) ? -ESRCH : -ENETUNREACH;
rcu_read_unlock();
@@ -398,7 +398,7 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp,
err = fib_table_lookup(tb, flp, res, flags);
if (err == -EAGAIN)
- err = -ENETUNREACH;
+ err = (flags & FIB_LOOKUP_REPORT_MISS) ? -ESRCH : -ENETUNREACH;
out:
rcu_read_unlock();
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 060501b376a8..3d7dcb8d0865 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -101,7 +101,7 @@ int __fib_lookup(struct net *net, struct flowi4 *flp,
res->tclassid = 0;
#endif
- if (err == -ESRCH)
+ if (err == -ESRCH && !(flags & FIB_LOOKUP_REPORT_MISS))
err = -ENETUNREACH;
return err;
--
2.47.3
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH net v2 2/4] ipv4: restrict on-link fallback to lookup misses
[not found] <20261110061536.10811-1-liamsmith827@grapheneos.org>
2026-11-10 6:15 ` [PATCH net v2 1/4] ipv4: add FIB_LOOKUP_REPORT_MISS liamsmith827
@ 2026-11-10 6:15 ` liamsmith827
2026-11-12 17:38 ` Jakub Kicinski
2026-11-10 6:15 ` [PATCH net v2 3/4] selftests: net: test restricted on-link fallback liamsmith827
2 siblings, 1 reply; 4+ messages in thread
From: liamsmith827 @ 2026-11-10 6:15 UTC (permalink / raw)
To: netdev
Cc: David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
linux-kselftest, linux-kernel, liamsmith827, stable
From: liamsmith827 <liamsmith827@proton.me>
For non-vrf unicast, the on-link fallback currently occurs regardless of
the particular error returned by fib_lookup(). As a result, routes and
rules that are supposed to restrict traffic (blackhole, prohibit,
unreachable) are unable to do so comprehensively.
A specific example of this being a problem is within Android, where the
VPN "kill switch" is implemented with prohibit rules. Any process that
can set flowi4_oif (SO_BINDTODEVICE, IP_UNICAST_IF, IP_PKTINFO, etc.) is
able to utilize this fallback, meaning unprivileged Android apps can
trivially bypass the VPN. This is particularly bad on cellular networks,
where ARP is often not needed.
Restrict the fallback to routing lookup misses.
This was originally observed on an Android device, by way of packet
capture.
Tested fcnal-test.sh in UML with CONFIG_IP_MULTIPLE_TABLES both enabled
and disabled.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: liamsmith827 <liamsmith827@proton.me>
---
net/ipv4/route.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 3a90c8d28b94..80a2c8a3c571 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2851,12 +2851,13 @@ struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *fl4,
goto make_route;
}
- err = fib_lookup(net, fl4, res, 0);
+ err = fib_lookup(net, fl4, res, FIB_LOOKUP_REPORT_MISS);
if (err) {
res->fi = NULL;
res->table = NULL;
if (fl4->flowi4_oif &&
- (ipv4_is_multicast(fl4->daddr) || !fl4->flowi4_l3mdev)) {
+ (ipv4_is_multicast(fl4->daddr) ||
+ (!fl4->flowi4_l3mdev && err == -ESRCH))) {
/* Apparently, routing tables are wrong. Assume,
* that the destination is on link.
*
@@ -2881,6 +2882,8 @@ struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *fl4,
res->type = RTN_UNICAST;
goto make_route;
}
+ /* Reverse the mapping induced by FIB_LOOKUP_REPORT_MISS. */
+ err = err == -ESRCH ? -ENETUNREACH : err;
rth = ERR_PTR(err);
goto out;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH net v2 2/4] ipv4: restrict on-link fallback to lookup misses
2026-11-10 6:15 ` [PATCH net v2 2/4] ipv4: restrict on-link fallback to lookup misses liamsmith827
@ 2026-11-12 17:38 ` Jakub Kicinski
0 siblings, 0 replies; 4+ messages in thread
From: Jakub Kicinski @ 2026-11-12 17:38 UTC (permalink / raw)
To: liamsmith827
Cc: netdev, David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Shuah Khan, linux-kselftest,
linux-kernel, liamsmith827, stable
On Tue, 10 Nov 2026 06:15:34 +0000 liamsmith827 wrote:
> From: liamsmith827 <liamsmith827@proton.me>
Author and SoB need to be your legal name with normal spelling.
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH net v2 3/4] selftests: net: test restricted on-link fallback
[not found] <20261110061536.10811-1-liamsmith827@grapheneos.org>
2026-11-10 6:15 ` [PATCH net v2 1/4] ipv4: add FIB_LOOKUP_REPORT_MISS liamsmith827
2026-11-10 6:15 ` [PATCH net v2 2/4] ipv4: restrict on-link fallback to lookup misses liamsmith827
@ 2026-11-10 6:15 ` liamsmith827
2 siblings, 0 replies; 4+ messages in thread
From: liamsmith827 @ 2026-11-10 6:15 UTC (permalink / raw)
To: netdev
Cc: David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
linux-kselftest, linux-kernel, liamsmith827, stable
From: liamsmith827 <liamsmith827@proton.me>
Update tests now that the on-link fallback has been restricted to
routing lookup misses for non-vrf unicast.
Cc: stable@vger.kernel.org
Signed-off-by: liamsmith827 <liamsmith827@proton.me>
---
tools/testing/selftests/net/fcnal-test.sh | 47 +++++++++++++----------
1 file changed, 26 insertions(+), 21 deletions(-)
diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index a50609535fed..c048d5be139d 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -619,17 +619,29 @@ ipv4_ping_novrf()
run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
log_test_addr ${a} $? 0 "ping local, device bind"
- # loopback addresses not reachable from device bind
- # fails in a really weird way though because ipv4 special cases
- # route lookups with oif set.
+ # loopback addresses not reachable from device bind, unreachable default route
for a in ${NSA_LO_IP} 127.0.0.1
do
log_start
show_hint "Fails since address on loopback device is out of device scope"
run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
- log_test_addr ${a} $? 1 "ping local, device bind"
+ log_test_addr ${a} $? 2 "ping local, device bind, unreachable default route"
done
+ # loopback addresses not reachable from device bind, route miss
+ log_start
+ setup_cmd ip route del unreachable default metric 8192
+
+ for a in ${NSA_LO_IP} 127.0.0.1
+ do
+ log_start
+ show_hint "Fails since address on loopback device is out of device scope"
+ run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_test_addr ${a} $? 1 "ping local, device bind, route miss"
+ done
+
+ setup_cmd ip route add unreachable default metric 8192
+
#
# ip rule blocks reachability to remote address
#
@@ -643,10 +655,9 @@ ipv4_ping_novrf()
run_cmd ping -c1 -w1 ${a}
log_test_addr ${a} $? 2 "ping out, blocked by rule"
- # NOTE: ipv4 actually allows the lookup to fail and yet still create
- # a viable rtable if the oif (e.g., bind to device) is set, so this
- # case succeeds despite the rule
- # run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_start
+ run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_test_addr ${a} $? 2 "ping out, device bind, blocked by rule"
a=${NSA_LO_IP}
log_start
@@ -671,10 +682,9 @@ ipv4_ping_novrf()
run_cmd ping -c1 -w1 ${a}
log_test_addr ${a} $? 2 "ping out, blocked by route"
- # NOTE: ipv4 actually allows the lookup to fail and yet still create
- # a viable rtable if the oif (e.g., bind to device) is set, so this
- # case succeeds despite not having a route for the address
- # run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_start
+ run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_test_addr ${a} $? 2 "ping out, device bind, blocked by route"
a=${NSA_LO_IP}
log_start
@@ -692,10 +702,9 @@ ipv4_ping_novrf()
run_cmd ping -c1 -w1 ${a}
log_test_addr ${a} $? 2 "ping out, unreachable default route"
- # NOTE: ipv4 actually allows the lookup to fail and yet still create
- # a viable rtable if the oif (e.g., bind to device) is set, so this
- # case succeeds despite not having a route for the address
- # run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_start
+ run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_test_addr ${a} $? 2 "ping out, device bind, unreachable default route"
}
ipv4_ping_vrf()
@@ -1602,10 +1611,6 @@ ipv4_udp_novrf()
run_cmd nettest -D -d ${NSA_DEV} -S -r ${a} -U
log_test_addr ${a} $? 0 "Global server, device client via IP_UNICAST_IF, local connection, with connect()"
-
- # IPv4 with device bind has really weird behavior - it overrides the
- # fib lookup, generates an rtable and tries to send the packet. This
- # causes failures for local traffic at different places
for a in ${NSA_LO_IP} 127.0.0.1
do
log_start
@@ -1613,7 +1618,7 @@ ipv4_udp_novrf()
run_cmd nettest -D -s &
wait_local_port_listen ${NSA} 12345 udp
run_cmd nettest -D -r ${a} -d ${NSA_DEV}
- log_test_addr ${a} $? 2 "Global server, device client, local connection"
+ log_test_addr ${a} $? 1 "Global server, device client, local connection"
log_start
show_hint "Should fail since addresses on loopback are out of device scope"
--
2.47.3
^ permalink raw reply related [flat|nested] 4+ messages in thread