]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
netfilter: nft_fwd_netdev: add device and headroom validate with neigh forwarding
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 27 Apr 2026 12:34:48 +0000 (14:34 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 29 Apr 2026 22:57:42 +0000 (00:57 +0200)
The ttl field has been decremented already and evaluation of this rule
would proceed, just drop this packet instead if there is no destination
device to forwards this packet. This is exactly what nf_dup already does
in this case.

Moreover, check for headroom and call skb_expand_head() like in the IP
output path to ensure there is sufficient headroom when forwarding this
via neigh_xmit().

Fixes: d32de98ea70f ("netfilter: nft_fwd_netdev: allow to forward packets via neighbour layer")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nft_fwd_netdev.c

index 2cc809303ce81d931dae6b52e5c0b8da076f78d6..605b1d42abce34474b35b43686cbc1506c92f9ce 100644 (file)
@@ -102,6 +102,7 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,
        struct sk_buff *skb = pkt->skb;
        int nhoff = skb_network_offset(skb);
        struct net_device *dev;
+       unsigned int hh_len;
        int neigh_table;
 
        switch (priv->nfproto) {
@@ -153,8 +154,19 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,
        }
 
        dev = dev_get_by_index_rcu(nft_net(pkt), oif);
-       if (dev == NULL)
-               return;
+       if (dev == NULL) {
+               verdict = NF_DROP;
+               goto out;
+       }
+
+       hh_len = LL_RESERVED_SPACE(dev);
+       if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
+               skb = skb_expand_head(skb, hh_len);
+               if (!skb) {
+                       verdict = NF_STOLEN;
+                       goto out;
+               }
+       }
 
        skb->dev = dev;
        skb_clear_tstamp(skb);