Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: bridge: move pskb_trim_rcsum out of br_nf_check_hbh_len

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>

authored by

Xin Long and committed by
Florian Westphal
0b24bd71 a7f1a2f4

+16 -21
+16 -21
net/bridge/br_netfilter_ipv6.c
··· 43 43 /* We only check the length. A bridge shouldn't do any hop-by-hop stuff 44 44 * anyway 45 45 */ 46 - static int br_nf_check_hbh_len(struct sk_buff *skb) 46 + static int br_nf_check_hbh_len(struct sk_buff *skb, u32 *plen) 47 47 { 48 48 int len, off = sizeof(struct ipv6hdr); 49 49 unsigned char *nh; 50 - u32 pkt_len; 51 50 52 51 if (!pskb_may_pull(skb, off + 8)) 53 52 return -1; ··· 74 75 return -1; 75 76 76 77 if (nh[off] == IPV6_TLV_JUMBO) { 78 + u32 pkt_len; 79 + 77 80 if (nh[off + 1] != 4 || (off & 3) != 2) 78 81 return -1; 79 82 pkt_len = ntohl(*(__be32 *)(nh + off + 2)); ··· 84 83 return -1; 85 84 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) 86 85 return -1; 87 - if (pskb_trim_rcsum(skb, 88 - pkt_len + sizeof(struct ipv6hdr))) 89 - return -1; 90 - nh = skb_network_header(skb); 86 + *plen = pkt_len; 91 87 } 92 88 off += optlen; 93 89 len -= optlen; ··· 112 114 goto inhdr_error; 113 115 114 116 pkt_len = ntohs(hdr->payload_len); 115 - 116 - if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { 117 - if (pkt_len + ip6h_len > skb->len) { 118 - __IP6_INC_STATS(net, idev, 119 - IPSTATS_MIB_INTRUNCATEDPKTS); 120 - goto drop; 121 - } 122 - if (pskb_trim_rcsum(skb, pkt_len + ip6h_len)) { 123 - __IP6_INC_STATS(net, idev, 124 - IPSTATS_MIB_INDISCARDS); 125 - goto drop; 126 - } 127 - hdr = ipv6_hdr(skb); 128 - } 129 - if (hdr->nexthdr == NEXTHDR_HOP && br_nf_check_hbh_len(skb)) 117 + if (hdr->nexthdr == NEXTHDR_HOP && br_nf_check_hbh_len(skb, &pkt_len)) 130 118 goto drop; 119 + 120 + if (pkt_len + ip6h_len > skb->len) { 121 + __IP6_INC_STATS(net, idev, 122 + IPSTATS_MIB_INTRUNCATEDPKTS); 123 + goto drop; 124 + } 125 + if (pskb_trim_rcsum(skb, pkt_len + ip6h_len)) { 126 + __IP6_INC_STATS(net, idev, 127 + IPSTATS_MIB_INDISCARDS); 128 + goto drop; 129 + } 131 130 132 131 memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); 133 132 /* No IP options in IPv6 header; however it should be