Message ID | 688b6037c640efeb6141d4646cc9dc1b657796e7.1677888566.git.lucien.xin@gmail.com |
---|---|
State | Changes Requested |
Delegated to: | Pablo Neira |
Headers | show |
Series | netfilter: handle ipv6 jumbo packets properly for bridge ovs and tc | expand |
On Fri, Mar 03, 2023 at 07:12:39PM -0500, Xin Long wrote: > 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> > --- > net/bridge/br_netfilter_ipv6.c | 33 ++++++++++++++------------------- > 1 file changed, 14 insertions(+), 19 deletions(-) > > diff --git a/net/bridge/br_netfilter_ipv6.c b/net/bridge/br_netfilter_ipv6.c > index 50f564c33551..07289e4f3213 100644 > --- a/net/bridge/br_netfilter_ipv6.c > +++ b/net/bridge/br_netfilter_ipv6.c > @@ -43,11 +43,11 @@ > /* 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; > + u32 pkt_len = 0; > > if (!pskb_may_pull(skb, off + 8)) > return -1; > @@ -83,10 +83,6 @@ 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); nit: Something you may want to consider if you spin a v2. It seems that pkt_len is only set here. So *plen could also be set here, simplifying the return path slightly. Also, if so, then a not entirely related clean-up would be to reduce the scope of pkt_len to this block. > } > off += optlen; > len -= optlen; > @@ -94,6 +90,8 @@ static int br_nf_check_hbh_len(struct sk_buff *skb) > if (len) > return -1; > > + if (pkt_len) > + *plen = pkt_len; > return 0; > } > ...
On 04/03/2023 02:12, Xin Long wrote: > 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> > --- > net/bridge/br_netfilter_ipv6.c | 33 ++++++++++++++------------------- > 1 file changed, 14 insertions(+), 19 deletions(-) > Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Xin Long <lucien.xin@gmail.com> writes: > 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: Aaron Conole <aconole@redhat.com> > net/bridge/br_netfilter_ipv6.c | 33 ++++++++++++++------------------- > 1 file changed, 14 insertions(+), 19 deletions(-) > > diff --git a/net/bridge/br_netfilter_ipv6.c b/net/bridge/br_netfilter_ipv6.c > index 50f564c33551..07289e4f3213 100644 > --- a/net/bridge/br_netfilter_ipv6.c > +++ b/net/bridge/br_netfilter_ipv6.c > @@ -43,11 +43,11 @@ > /* 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; > + u32 pkt_len = 0; > > if (!pskb_may_pull(skb, off + 8)) > return -1; > @@ -83,10 +83,6 @@ 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); > } > off += optlen; > len -= optlen; > @@ -94,6 +90,8 @@ static int br_nf_check_hbh_len(struct sk_buff *skb) > if (len) > return -1; > > + if (pkt_len) > + *plen = pkt_len; > return 0; > } > > @@ -116,22 +114,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
diff --git a/net/bridge/br_netfilter_ipv6.c b/net/bridge/br_netfilter_ipv6.c index 50f564c33551..07289e4f3213 100644 --- a/net/bridge/br_netfilter_ipv6.c +++ b/net/bridge/br_netfilter_ipv6.c @@ -43,11 +43,11 @@ /* 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; + u32 pkt_len = 0; if (!pskb_may_pull(skb, off + 8)) return -1; @@ -83,10 +83,6 @@ 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); } off += optlen; len -= optlen; @@ -94,6 +90,8 @@ static int br_nf_check_hbh_len(struct sk_buff *skb) if (len) return -1; + if (pkt_len) + *plen = pkt_len; return 0; } @@ -116,22 +114,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
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> --- net/bridge/br_netfilter_ipv6.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-)