]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
netfilter: nf_socket: skip socket lookup for non-first fragments
authorFernando Fernandez Mancera <fmancera@suse.de>
Tue, 28 Apr 2026 10:25:46 +0000 (12:25 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 30 Apr 2026 15:59:01 +0000 (17:59 +0200)
Both nft_socket and xt_socket relies on L4 headers to perform socket
lookup in the slow path. For fragmented packets, while the IP protocol
remains constant across all fragments, only the first fragment contains
the actual L4 header.

As the expression/match could be attached to a chain with a priority
lower than -400, it could bypass defragmentation.

Add a check for fragmentation in the lookup functions directly so the
problem is handled for both nft_socket and xt_socket at the same time.
In addition, future users of the functions would not need to care about
this.

Fixes: 902d6a4c2a4f ("netfilter: nf_defrag: Skip defrag if NOTRACK is set")
Fixes: 554ced0a6e29 ("netfilter: nf_tables: add support for native socket matching")
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/ipv4/netfilter/nf_socket_ipv4.c
net/ipv6/netfilter/nf_socket_ipv6.c

index 5080fa5fbf6a025b11f44268a73989cbfc09e65e..f9c6755f5ec576bc3009dca916a7cf395464ab22 100644 (file)
@@ -94,6 +94,9 @@ struct sock *nf_sk_lookup_slow_v4(struct net *net, const struct sk_buff *skb,
 #endif
        int doff = 0;
 
+       if (ntohs(iph->frag_off) & IP_OFFSET)
+               return NULL;
+
        if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) {
                struct tcphdr _hdr;
                struct udphdr *hp;
index ced8bd44828ef70442b99fb1dfc94cfead0832c0..893f2aeb4711458bb7711d186c434c58cdf25d5b 100644 (file)
@@ -100,6 +100,7 @@ struct sock *nf_sk_lookup_slow_v6(struct net *net, const struct sk_buff *skb,
        const struct in6_addr *daddr = NULL, *saddr = NULL;
        struct ipv6hdr *iph = ipv6_hdr(skb), ipv6_var;
        struct sk_buff *data_skb = NULL;
+       unsigned short fragoff = 0;
        int doff = 0;
        int thoff = 0, tproto;
 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
@@ -107,8 +108,8 @@ struct sock *nf_sk_lookup_slow_v6(struct net *net, const struct sk_buff *skb,
        struct nf_conn const *ct;
 #endif
 
-       tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
-       if (tproto < 0) {
+       tproto = ipv6_find_hdr(skb, &thoff, -1, &fragoff, NULL);
+       if (tproto < 0 || fragoff) {
                pr_debug("unable to find transport header in IPv6 packet, dropping\n");
                return NULL;
        }