bpf: bpf_fib_lookup should not return neigh in NUD_FAILED state
authorMartin KaFai Lau <martin.lau@kernel.org>
Fri, 17 Feb 2023 00:41:48 +0000 (16:41 -0800)
committerDaniel Borkmann <daniel@iogearbox.net>
Fri, 17 Feb 2023 15:19:42 +0000 (16:19 +0100)
The bpf_fib_lookup() helper does not only look up the fib (ie. route)
but it also looks up the neigh. Before returning the neigh, the helper
does not check for NUD_VALID. When a neigh state (neigh->nud_state)
is in NUD_FAILED, its dmac (neigh->ha) could be all zeros. The helper
still returns SUCCESS instead of NO_NEIGH in this case. Because of the
SUCCESS return value, the bpf prog directly uses the returned dmac
and ends up filling all zero in the eth header.

This patch checks for NUD_VALID and returns NO_NEIGH if the neigh is
not valid.

Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20230217004150.2980689-3-martin.lau@linux.dev
net/core/filter.c

index 2ce06a72a5bae7011e665438c942b4c77e0fb1d3..8daaaf76ab15047f8cf13ff073d41a2737707fe2 100644 (file)
@@ -5849,7 +5849,7 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
                neigh = __ipv6_neigh_lookup_noref_stub(dev, dst);
        }
 
-       if (!neigh)
+       if (!neigh || !(neigh->nud_state & NUD_VALID))
                return BPF_FIB_LKUP_RET_NO_NEIGH;
 
        return bpf_fib_set_fwd_params(params, neigh, dev, mtu);
@@ -5964,7 +5964,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
         * not needed here.
         */
        neigh = __ipv6_neigh_lookup_noref_stub(dev, dst);
-       if (!neigh)
+       if (!neigh || !(neigh->nud_state & NUD_VALID))
                return BPF_FIB_LKUP_RET_NO_NEIGH;
 
        return bpf_fib_set_fwd_params(params, neigh, dev, mtu);