[ovs-dev,v2] flow: fix incorrect padding length checking and combine branch in ipv6_sanity_check
diff mbox series

Message ID 1566468574-21240-1-git-send-email-Yanqin.Wei@arm.com
State New
Headers show
Series
  • [ovs-dev,v2] flow: fix incorrect padding length checking and combine branch in ipv6_sanity_check
Related show

Commit Message

Yanqin Wei Aug. 22, 2019, 10:09 a.m. UTC
The padding length is (packet size - ipv6 header length - ipv6 plen).  This
patch fixes incorrect ipv6 size checking and improves it by combining branch.

Reviewed-by: Gavin Hu <Gavin.Hu@arm.com>
Signed-off-by: Yanqin Wei <Yanqin.Wei@arm.com>
---
 lib/flow.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

Comments

Ben Pfaff Aug. 28, 2019, 9:58 p.m. UTC | #1
On Thu, Aug 22, 2019 at 06:09:34PM +0800, Yanqin Wei wrote:
> The padding length is (packet size - ipv6 header length - ipv6 plen).  This
> patch fixes incorrect ipv6 size checking and improves it by combining branch.
> 
> Reviewed-by: Gavin Hu <Gavin.Hu@arm.com>
> Signed-off-by: Yanqin Wei <Yanqin.Wei@arm.com>
> ---
>  lib/flow.c | 10 ++++------
>  1 file changed, 4 insertions(+), 6 deletions(-)
> 
> diff --git a/lib/flow.c b/lib/flow.c
> index e5b554b..1b21f51 100644
> --- a/lib/flow.c
> +++ b/lib/flow.c
> @@ -688,18 +688,16 @@ ipv4_get_nw_frag(const struct ip_header *nh)
>  static inline bool
>  ipv6_sanity_check(const struct ovs_16aligned_ip6_hdr *nh, size_t size)
>  {
> -    uint16_t plen;
> +    int pad_len;
>  
>      if (OVS_UNLIKELY(size < sizeof *nh)) {
>          return false;
>      }
>  
> -    plen = ntohs(nh->ip6_plen);
> -    if (OVS_UNLIKELY(plen + IPV6_HEADER_LEN > size)) {
> -        return false;
> -    }
> +    pad_len = size - IPV6_HEADER_LEN - ntohs(nh->ip6_plen);

The types in the above calculation worry me.  Writing the type of each
term:

    int = size_t - int - uint16_t

The most likely type of the right side of the expression is size_t.
Assigning this to an 'int' might do "the right thing" for negative
values, but it's risky--especially since size_t and int might be
different widths.  I think it would be safer to cast the first and third
terms to int, e.g.:

    pad_len = (int) size - IPV6_HEADER_LEN - (int) ntohs(nh->ip6_plen);

>      /* Jumbo Payload option not supported yet. */
> -    if (OVS_UNLIKELY(size - plen > UINT8_MAX)) {
> +    if (OVS_UNLIKELY(pad_len < 0 || pad_len > UINT8_MAX)) {
>          return false;
>      }

Thanks,

Ben.
Yanqin Wei Aug. 29, 2019, 8:21 a.m. UTC | #2
Hi Ben,

Thanks for the comments. I am sorry not to notice the risk of calculation with different type . 
The original reason to use 'int' for size checking is that compiler can combine two conditions into one and save a branch instruction here,  because "negative value" always more than UINT8_MAX.  
> +    if (OVS_UNLIKELY(pad_len < 0 || pad_len > UINT8_MAX)) {

But now I realized it introduces the risk and not clean for C code even if we use type cast here. So I will remove this performance improvement and only keep the bug fix for padding length calculation in this patch. What do you think of it?

Best Regards,
Wei Yanqin

-----Original Message-----
From: Ben Pfaff <blp@ovn.org> 
Sent: Thursday, August 29, 2019 5:58 AM
To: Yanqin Wei (Arm Technology China) <Yanqin.Wei@arm.com>
Cc: dev@openvswitch.org; nd <nd@arm.com>; Gavin Hu (Arm Technology China) <Gavin.Hu@arm.com>
Subject: Re: [ovs-dev] [PATCH v2] flow: fix incorrect padding length checking and combine branch in ipv6_sanity_check

On Thu, Aug 22, 2019 at 06:09:34PM +0800, Yanqin Wei wrote:
> The padding length is (packet size - ipv6 header length - ipv6 plen).  
> This patch fixes incorrect ipv6 size checking and improves it by combining branch.
> 
> Reviewed-by: Gavin Hu <Gavin.Hu@arm.com>
> Signed-off-by: Yanqin Wei <Yanqin.Wei@arm.com>
> ---
>  lib/flow.c | 10 ++++------
>  1 file changed, 4 insertions(+), 6 deletions(-)
> 
> diff --git a/lib/flow.c b/lib/flow.c
> index e5b554b..1b21f51 100644
> --- a/lib/flow.c
> +++ b/lib/flow.c
> @@ -688,18 +688,16 @@ ipv4_get_nw_frag(const struct ip_header *nh)  
> static inline bool  ipv6_sanity_check(const struct 
> ovs_16aligned_ip6_hdr *nh, size_t size)  {
> -    uint16_t plen;
> +    int pad_len;
>  
>      if (OVS_UNLIKELY(size < sizeof *nh)) {
>          return false;
>      }
>  
> -    plen = ntohs(nh->ip6_plen);
> -    if (OVS_UNLIKELY(plen + IPV6_HEADER_LEN > size)) {
> -        return false;
> -    }
> +    pad_len = size - IPV6_HEADER_LEN - ntohs(nh->ip6_plen);

The types in the above calculation worry me.  Writing the type of each
term:

    int = size_t - int - uint16_t

The most likely type of the right side of the expression is size_t.
Assigning this to an 'int' might do "the right thing" for negative values, but it's risky--especially since size_t and int might be different widths.  I think it would be safer to cast the first and third terms to int, e.g.:

    pad_len = (int) size - IPV6_HEADER_LEN - (int) ntohs(nh->ip6_plen);

>      /* Jumbo Payload option not supported yet. */
> -    if (OVS_UNLIKELY(size - plen > UINT8_MAX)) {
> +    if (OVS_UNLIKELY(pad_len < 0 || pad_len > UINT8_MAX)) {
>          return false;
>      }

Thanks,

Ben.
Ben Pfaff Aug. 29, 2019, 2:22 p.m. UTC | #3
The bug fix should definitely go in.  Maybe the performance improvement
could be separated.

On Thu, Aug 29, 2019 at 08:21:22AM +0000, Yanqin Wei (Arm Technology China) wrote:
> Hi Ben,
> 
> Thanks for the comments. I am sorry not to notice the risk of calculation with different type . 
> The original reason to use 'int' for size checking is that compiler can combine two conditions into one and save a branch instruction here,  because "negative value" always more than UINT8_MAX.  
> > +    if (OVS_UNLIKELY(pad_len < 0 || pad_len > UINT8_MAX)) {
> 
> But now I realized it introduces the risk and not clean for C code even if we use type cast here. So I will remove this performance improvement and only keep the bug fix for padding length calculation in this patch. What do you think of it?
> 
> Best Regards,
> Wei Yanqin
> 
> -----Original Message-----
> From: Ben Pfaff <blp@ovn.org> 
> Sent: Thursday, August 29, 2019 5:58 AM
> To: Yanqin Wei (Arm Technology China) <Yanqin.Wei@arm.com>
> Cc: dev@openvswitch.org; nd <nd@arm.com>; Gavin Hu (Arm Technology China) <Gavin.Hu@arm.com>
> Subject: Re: [ovs-dev] [PATCH v2] flow: fix incorrect padding length checking and combine branch in ipv6_sanity_check
> 
> On Thu, Aug 22, 2019 at 06:09:34PM +0800, Yanqin Wei wrote:
> > The padding length is (packet size - ipv6 header length - ipv6 plen).  
> > This patch fixes incorrect ipv6 size checking and improves it by combining branch.
> > 
> > Reviewed-by: Gavin Hu <Gavin.Hu@arm.com>
> > Signed-off-by: Yanqin Wei <Yanqin.Wei@arm.com>
> > ---
> >  lib/flow.c | 10 ++++------
> >  1 file changed, 4 insertions(+), 6 deletions(-)
> > 
> > diff --git a/lib/flow.c b/lib/flow.c
> > index e5b554b..1b21f51 100644
> > --- a/lib/flow.c
> > +++ b/lib/flow.c
> > @@ -688,18 +688,16 @@ ipv4_get_nw_frag(const struct ip_header *nh)  
> > static inline bool  ipv6_sanity_check(const struct 
> > ovs_16aligned_ip6_hdr *nh, size_t size)  {
> > -    uint16_t plen;
> > +    int pad_len;
> >  
> >      if (OVS_UNLIKELY(size < sizeof *nh)) {
> >          return false;
> >      }
> >  
> > -    plen = ntohs(nh->ip6_plen);
> > -    if (OVS_UNLIKELY(plen + IPV6_HEADER_LEN > size)) {
> > -        return false;
> > -    }
> > +    pad_len = size - IPV6_HEADER_LEN - ntohs(nh->ip6_plen);
> 
> The types in the above calculation worry me.  Writing the type of each
> term:
> 
>     int = size_t - int - uint16_t
> 
> The most likely type of the right side of the expression is size_t.
> Assigning this to an 'int' might do "the right thing" for negative values, but it's risky--especially since size_t and int might be different widths.  I think it would be safer to cast the first and third terms to int, e.g.:
> 
>     pad_len = (int) size - IPV6_HEADER_LEN - (int) ntohs(nh->ip6_plen);
> 
> >      /* Jumbo Payload option not supported yet. */
> > -    if (OVS_UNLIKELY(size - plen > UINT8_MAX)) {
> > +    if (OVS_UNLIKELY(pad_len < 0 || pad_len > UINT8_MAX)) {
> >          return false;
> >      }
> 
> Thanks,
> 
> Ben.

Patch
diff mbox series

diff --git a/lib/flow.c b/lib/flow.c
index e5b554b..1b21f51 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -688,18 +688,16 @@  ipv4_get_nw_frag(const struct ip_header *nh)
 static inline bool
 ipv6_sanity_check(const struct ovs_16aligned_ip6_hdr *nh, size_t size)
 {
-    uint16_t plen;
+    int pad_len;
 
     if (OVS_UNLIKELY(size < sizeof *nh)) {
         return false;
     }
 
-    plen = ntohs(nh->ip6_plen);
-    if (OVS_UNLIKELY(plen + IPV6_HEADER_LEN > size)) {
-        return false;
-    }
+    pad_len = size - IPV6_HEADER_LEN - ntohs(nh->ip6_plen);
+
     /* Jumbo Payload option not supported yet. */
-    if (OVS_UNLIKELY(size - plen > UINT8_MAX)) {
+    if (OVS_UNLIKELY(pad_len < 0 || pad_len > UINT8_MAX)) {
         return false;
     }