]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
netfilter: nf_tables: set transport offset from mac header for netdev/egress
authorPablo Neira Ayuso <pablo@netfilter.org>
Thu, 14 Dec 2023 10:50:12 +0000 (11:50 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 10 Jan 2024 16:10:21 +0000 (17:10 +0100)
[ Upstream commit 0ae8e4cca78781401b17721bfb72718fdf7b4912 ]

Before this patch, transport offset (pkt->thoff) provides an offset
relative to the network header. This is fine for the inet families
because skb->data points to the network header in such case. However,
from netdev/egress, skb->data points to the mac header (if available),
thus, pkt->thoff is missing the mac header length.

Add skb_network_offset() to the transport offset (pkt->thoff) for
netdev, so transport header mangling works as expected. Adjust payload
fast eval function to use skb->data now that pkt->thoff provides an
absolute offset. This explains why users report that matching on
egress/netdev works but payload mangling does not.

This patch implicitly fixes payload mangling for IPv4 packets in
netdev/egress given skb_store_bits() requires an offset from skb->data
to reach the transport header.

I suspect that nft_exthdr and the trace infra were also broken from
netdev/egress because they also take skb->data as start, and pkt->thoff
was not correct.

Note that IPv6 is fine because ipv6_find_hdr() already provides a
transport offset starting from skb->data, which includes
skb_network_offset().

The bridge family also uses nft_set_pktinfo_ipv4_validate(), but there
skb_network_offset() is zero, so the update in this patch does not alter
the existing behaviour.

Fixes: 42df6e1d221d ("netfilter: Introduce egress hook")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/net/netfilter/nf_tables_ipv4.h
net/netfilter/nf_tables_core.c

index d8f6cb47ebe379d6350d45588312345cecaa7ffc..5225d2bd1a6e99856eb6dbdb9c668ea51b7ccdc0 100644 (file)
@@ -30,7 +30,7 @@ static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
                return -1;
 
        len = iph_totlen(pkt->skb, iph);
-       thoff = iph->ihl * 4;
+       thoff = skb_network_offset(pkt->skb) + (iph->ihl * 4);
        if (pkt->skb->len < len)
                return -1;
        else if (len < thoff)
index cee3e4e905ec8809f9af426c7ee6a011c5748fff..e0c117229ee9d2c01efdffcaadf712f92cbc0479 100644 (file)
@@ -141,7 +141,7 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr,
        else {
                if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
                        return false;
-               ptr = skb_network_header(skb) + nft_thoff(pkt);
+               ptr = skb->data + nft_thoff(pkt);
        }
 
        ptr += priv->offset;