When Linux forwards a packet and needs to generate an ICMP error, icmp_route_lookup() performs a reverse-path relookup. For non-local destinations, it performs a decoy lookup via ip_route_output_key() to find the expected egress interface (rt2->dst.dev) before validating the path with ip_route_input(). Currently, the decoy flow structure (fl4_2) only sets .daddr = fl4_dec.saddr, leaving .saddr, .flowi4_dscp, .flowi4_proto, .flowi4_mark, and .flowi4_uid zeroed out. When policy routing rules (such as ip rule add from $SRC lookup 100, or dscp/fwmark/ipproto rules) are configured: 1. ip_route_output_key() fails to match the policy rule because saddr and other key flow selectors are missing in fl4_2. 2. It resolves a route using the default table instead, returning an incorrect egress netdev. 3. Passing the wrong netdev to ip_route_input() causes strict reverse-path filtering (rp_filter=1) to fail, logging false-positive "martian source" warnings and causing the relookup to fail. Fix this by populating fl4_2 with .saddr = fl4_dec.daddr, .flowi4_dscp, .flowi4_proto = IPPROTO_ICMP, .flowi4_mark, and .flowi4_uid so that ip_route_output_key() selects the correct egress interface matching policy routing rules. Fixes: 415b3334a21a ("icmp: Fix regression in nexthop resolution during replies.") Reported-by: Muhammad Ziad Closes: https://lore.kernel.org/netdev/CAOAwikA60AYKdFr_UDLyja3oU4hqyAE7uFZWqum5uRdaQsgRYg@mail.gmail.com/ Signed-off-by: Eric Dumazet --- net/ipv4/icmp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 23e921d313b36b00d8ae5e14846527220c9db32b..2259f643cb0d43ea54819dd831c79807413e0d69 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -548,10 +548,16 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4, if (IS_ERR(rt2)) err = PTR_ERR(rt2); } else { - struct flowi4 fl4_2 = {}; + struct flowi4 fl4_2 = { + .daddr = fl4_dec.saddr, + .saddr = fl4_dec.daddr, + .flowi4_dscp = dscp, + .flowi4_proto = IPPROTO_ICMP, + .flowi4_mark = mark, + .flowi4_uid = sock_net_uid(net, NULL), + }; unsigned long orefdst; - fl4_2.daddr = fl4_dec.saddr; rt2 = ip_route_output_key(net, &fl4_2); if (IS_ERR(rt2)) { err = PTR_ERR(rt2); -- 2.55.0.141.g00534a21ce-goog