netfilter: bridge: move pskb_trim_rcsum out of br_nf_check_hbh_len
authorXin Long <lucien.xin@gmail.com>
Tue, 7 Mar 2023 21:31:29 +0000 (16:31 -0500)
committerFlorian Westphal <fw@strlen.de>
Wed, 8 Mar 2023 13:25:40 +0000 (14:25 +0100)
br_nf_check_hbh_len() is a function to check the Hop-by-hop option
header, and shouldn't do pskb_trim_rcsum() there. This patch is to
pass pkt_len out to br_validate_ipv6() and do pskb_trim_rcsum()
after calling br_validate_ipv6() instead.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Reviewed-by: Aaron Conole <aconole@redhat.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
net/bridge/br_netfilter_ipv6.c

index 8be3c5c..a0d6dfb 100644 (file)
 /* We only check the length. A bridge shouldn't do any hop-by-hop stuff
  * anyway
  */
-static int br_nf_check_hbh_len(struct sk_buff *skb)
+static int br_nf_check_hbh_len(struct sk_buff *skb, u32 *plen)
 {
        int len, off = sizeof(struct ipv6hdr);
        unsigned char *nh;
-       u32 pkt_len;
 
        if (!pskb_may_pull(skb, off + 8))
                return -1;
@@ -75,6 +74,8 @@ static int br_nf_check_hbh_len(struct sk_buff *skb)
                        return -1;
 
                if (nh[off] == IPV6_TLV_JUMBO) {
+                       u32 pkt_len;
+
                        if (nh[off + 1] != 4 || (off & 3) != 2)
                                return -1;
                        pkt_len = ntohl(*(__be32 *)(nh + off + 2));
@@ -83,10 +84,7 @@ static int br_nf_check_hbh_len(struct sk_buff *skb)
                                return -1;
                        if (pkt_len > skb->len - sizeof(struct ipv6hdr))
                                return -1;
-                       if (pskb_trim_rcsum(skb,
-                                           pkt_len + sizeof(struct ipv6hdr)))
-                               return -1;
-                       nh = skb_network_header(skb);
+                       *plen = pkt_len;
                }
                off += optlen;
                len -= optlen;
@@ -114,22 +112,19 @@ int br_validate_ipv6(struct net *net, struct sk_buff *skb)
                goto inhdr_error;
 
        pkt_len = ntohs(hdr->payload_len);
+       if (hdr->nexthdr == NEXTHDR_HOP && br_nf_check_hbh_len(skb, &pkt_len))
+               goto drop;
 
-       if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
-               if (pkt_len + ip6h_len > skb->len) {
-                       __IP6_INC_STATS(net, idev,
-                                       IPSTATS_MIB_INTRUNCATEDPKTS);
-                       goto drop;
-               }
-               if (pskb_trim_rcsum(skb, pkt_len + ip6h_len)) {
-                       __IP6_INC_STATS(net, idev,
-                                       IPSTATS_MIB_INDISCARDS);
-                       goto drop;
-               }
-               hdr = ipv6_hdr(skb);
+       if (pkt_len + ip6h_len > skb->len) {
+               __IP6_INC_STATS(net, idev,
+                               IPSTATS_MIB_INTRUNCATEDPKTS);
+               goto drop;
        }
-       if (hdr->nexthdr == NEXTHDR_HOP && br_nf_check_hbh_len(skb))
+       if (pskb_trim_rcsum(skb, pkt_len + ip6h_len)) {
+               __IP6_INC_STATS(net, idev,
+                               IPSTATS_MIB_INDISCARDS);
                goto drop;
+       }
 
        memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
        /* No IP options in IPv6 header; however it should be