]> git.ipfire.org Git - thirdparty/kernel/linux.git/commit
bpf: zero-initialize the fib lookup flow struct
authorAvinash Duduskar <avinash.duduskar@gmail.com>
Wed, 17 Jun 2026 22:47:19 +0000 (04:17 +0530)
committerAlexei Starovoitov <ast@kernel.org>
Mon, 22 Jun 2026 01:07:53 +0000 (18:07 -0700)
commit0dfcb68a6a5ac517b22dff6a1f01cb4f126dfc57
treeddea6cb3e33c6989218151930f2709008b2eb678
parentbda6a7308ef8e79cfbb7d09e48e1c7ffaa522269
bpf: zero-initialize the fib lookup flow struct

bpf_ipv4_fib_lookup() and bpf_ipv6_fib_lookup() build the flow key on
the stack with a bare "struct flowi4 fl4;" / "struct flowi6 fl6;" and
fill it field by field, but never set flowi4_l3mdev / flowi6_l3mdev.

On the non-DIRECT path the lookup goes through the fib rules whenever the
netns has custom rules, which a VRF installs:

bpf_ipv4_fib_lookup() -> fib_lookup() -> __fib_lookup()
  -> l3mdev_update_flow()   reads !fl->flowi_l3mdev
  -> fib_rules_lookup() -> fib_rule_match()
       -> l3mdev_fib_rule_match()   uses fl->flowi_l3mdev

l3mdev_update_flow() resolves the l3mdev master from the ingress device
only while the field is still zero. Left at a nonzero stack value the
resolution is skipped, and l3mdev_fib_rule_match() then tests that value
as an ifindex, so the VRF master is not resolved and the rule fails to
match: an ingress enslaved to a VRF can fail to select its table. FIB
rules matching on an L3 master device (l3mdev_fib_rule_iif_match()/
_oif_match()) read the same value, so an "ip rule iif/oif <vrf>"
mismatches the same way.

Zero-initialize the whole flow struct rather than adding one more
field assignment, so any flowi field added later is covered too.
ip_route_input_slow() likewise zeroes the field before its input lookup.

CONFIG_INIT_STACK_ALL_ZERO masks this by default, but it depends on
compiler support (CC_HAS_AUTO_VAR_INIT_ZERO), so INIT_STACK_NONE builds,
including older toolchains that fall back to it, are exposed. Built with
INIT_STACK_ALL_PATTERN, a plain bpf_fib_lookup (no VLAN, no DIRECT) over a
VRF slave whose destination is routed only in the VRF table returns
BPF_FIB_LKUP_RET_NOT_FWDED, and resolves with this patch. On the default
config the lookup succeeds either way, so ordinary testing does not catch
the bug.

Fixes: 40867d74c374 ("net: Add l3mdev index to flow struct and avoid oif reset for port devices")
Signed-off-by: Avinash Duduskar <avinash.duduskar@gmail.com>
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/r/20260617224719.1428599-1-avinash.duduskar@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
net/core/filter.c