netfilter: keep conntrack reference until IPsecv6 policy checks are done
authorMadhu Koriginja <madhu.koriginja@nxp.com>
Tue, 21 Mar 2023 15:58:44 +0000 (21:28 +0530)
committerFlorian Westphal <fw@strlen.de>
Wed, 22 Mar 2023 20:50:23 +0000 (21:50 +0100)
Keep the conntrack reference until policy checks have been performed for
IPsec V6 NAT support, just like ipv4.

The reference needs to be dropped before a packet is
queued to avoid having the conntrack module unloadable.

Fixes: 58a317f1061c ("netfilter: ipv6: add IPv6 NAT support")
Signed-off-by: Madhu Koriginja <madhu.koriginja@nxp.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
net/dccp/ipv6.c
net/ipv6/ip6_input.c
net/ipv6/raw.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c

index 47fb108..93c9899 100644 (file)
@@ -784,6 +784,7 @@ lookup:
 
        if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
                goto discard_and_relse;
+       nf_reset_ct(skb);
 
        return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
                                refcounted) ? -1 : 0;
index e1ebf5e..d94041b 100644 (file)
@@ -404,10 +404,6 @@ resubmit_final:
                        /* Only do this once for first final protocol */
                        have_final = true;
 
-                       /* Free reference early: we don't need it any more,
-                          and it may hold ip_conntrack module loaded
-                          indefinitely. */
-                       nf_reset_ct(skb);
 
                        skb_postpull_rcsum(skb, skb_network_header(skb),
                                           skb_network_header_len(skb));
@@ -430,10 +426,12 @@ resubmit_final:
                                goto discard;
                        }
                }
-               if (!(ipprot->flags & INET6_PROTO_NOPOLICY) &&
-                   !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
-                       SKB_DR_SET(reason, XFRM_POLICY);
-                       goto discard;
+               if (!(ipprot->flags & INET6_PROTO_NOPOLICY)) {
+                       if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+                               SKB_DR_SET(reason, XFRM_POLICY);
+                               goto discard;
+                       }
+                       nf_reset_ct(skb);
                }
 
                ret = INDIRECT_CALL_2(ipprot->handler, tcp_v6_rcv, udpv6_rcv,
index 6ac2f26..4ab62a9 100644 (file)
@@ -194,10 +194,8 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
                        struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
 
                        /* Not releasing hash table! */
-                       if (clone) {
-                               nf_reset_ct(clone);
+                       if (clone)
                                rawv6_rcv(sk, clone);
-                       }
                }
        }
        rcu_read_unlock();
@@ -391,6 +389,7 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
                kfree_skb_reason(skb, SKB_DROP_REASON_XFRM_POLICY);
                return NET_RX_DROP;
        }
+       nf_reset_ct(skb);
 
        if (!rp->checksum)
                skb->ip_summed = CHECKSUM_UNNECESSARY;
index 35cf523..244cf86 100644 (file)
@@ -1723,6 +1723,8 @@ process:
        if (drop_reason)
                goto discard_and_relse;
 
+       nf_reset_ct(skb);
+
        if (tcp_filter(sk, skb)) {
                drop_reason = SKB_DROP_REASON_SOCKET_FILTER;
                goto discard_and_relse;
index d350e57..4caa70a 100644 (file)
@@ -704,6 +704,7 @@ static int udpv6_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)
                drop_reason = SKB_DROP_REASON_XFRM_POLICY;
                goto drop;
        }
+       nf_reset_ct(skb);
 
        if (static_branch_unlikely(&udpv6_encap_needed_key) && up->encap_type) {
                int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
@@ -1027,6 +1028,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
 
        if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
                goto discard;
+       nf_reset_ct(skb);
 
        if (udp_lib_checksum_complete(skb))
                goto csum_error;