netfilter: nft_payload: don't allow th access for fragments
authorFlorian Westphal <fw@strlen.de>
Sat, 29 Jan 2022 16:13:23 +0000 (17:13 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 4 Feb 2022 04:38:15 +0000 (05:38 +0100)
Loads relative to ->thoff naturally expect that this points to the
transport header, but this is only true if pkt->fragoff == 0.

This has little effect for rulesets with connection tracking/nat because
these enable ip defra. For other rulesets this prevents false matches.

Fixes: 96518518cc41 ("netfilter: add nftables")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nft_exthdr.c
net/netfilter/nft_payload.c

index dbe1f2e7dd9ed620b1ab0c99c214178e6dbc6a16..9e927ab4df151095612e6878ca571ddf8c5f0b6d 100644 (file)
@@ -167,7 +167,7 @@ nft_tcp_header_pointer(const struct nft_pktinfo *pkt,
 {
        struct tcphdr *tcph;
 
-       if (pkt->tprot != IPPROTO_TCP)
+       if (pkt->tprot != IPPROTO_TCP || pkt->fragoff)
                return NULL;
 
        tcph = skb_header_pointer(pkt->skb, nft_thoff(pkt), sizeof(*tcph), buffer);
index 940fed9a760b3f987d5558af5293a527bc333696..5cc06aef43452a8dcd30bb38e4dd6b0865566ed7 100644 (file)
@@ -83,7 +83,7 @@ static int __nft_payload_inner_offset(struct nft_pktinfo *pkt)
 {
        unsigned int thoff = nft_thoff(pkt);
 
-       if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+       if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
                return -1;
 
        switch (pkt->tprot) {
@@ -147,7 +147,7 @@ void nft_payload_eval(const struct nft_expr *expr,
                offset = skb_network_offset(skb);
                break;
        case NFT_PAYLOAD_TRANSPORT_HEADER:
-               if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+               if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
                        goto err;
                offset = nft_thoff(pkt);
                break;
@@ -688,7 +688,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
                offset = skb_network_offset(skb);
                break;
        case NFT_PAYLOAD_TRANSPORT_HEADER:
-               if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+               if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
                        goto err;
                offset = nft_thoff(pkt);
                break;
@@ -728,7 +728,8 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
        if (priv->csum_type == NFT_PAYLOAD_CSUM_SCTP &&
            pkt->tprot == IPPROTO_SCTP &&
            skb->ip_summed != CHECKSUM_PARTIAL) {
-               if (nft_payload_csum_sctp(skb, nft_thoff(pkt)))
+               if (pkt->fragoff == 0 &&
+                   nft_payload_csum_sctp(skb, nft_thoff(pkt)))
                        goto err;
        }