[ovs-dev,v2] conntrack: Fix ICMPv4 error data L4 length check.
diff mbox series

Message ID 1566950342-51171-1-git-send-email-dlu998@gmail.com
State New
Headers show
Series
  • [ovs-dev,v2] conntrack: Fix ICMPv4 error data L4 length check.
Related show

Commit Message

Darrell Ball Aug. 27, 2019, 11:59 p.m. UTC
The ICMPv4 error data L4 length check was found to be too strict for TCP,
expecting a minimum of 20 rather than 8 bytes.  This worked by
hapenstance for other inner protocols.  The approach is to explicitly
handle the ICMPv4 error data L4 length check and to do this for all
supported inner protocols in the same way.  Making the code common
between protocols also allows the existing ICMPv4 related UDP tests to
cover TCP and ICMP inner protocol cases.
Note that ICMPv6 does not have an 8 byte limit for error L4 data.

Fixes: a489b16854b5 ("conntrack: New userspace connection tracker.")
CC: Daniele Di Proietto <diproiettod@ovn.org>
Reported-at: https://mail.openvswitch.org/pipermail/ovs-dev/2019-August/361949.html
Reported-by: Vishal Deep Ajmera <vishal.deep.ajmera@ericsson.com>
Signed-off-by: Vishal Deep Ajmera <vishal.deep.ajmera@ericsson.com>
Co-authored-by: Vishal Deep Ajmera <vishal.deep.ajmera@ericsson.com>
Signed-off-by: Darrell Ball <dlu998@gmail.com>
---

v2: Rebase to fix git applying to wrong function (extract_l4_icmp6 vs
    extract_l4_icmp) with same match signature.

    Minor fix to related comment in extract_l4().
    

 lib/conntrack.c | 41 ++++++++++++++++++++++++-----------------
 lib/packets.h   |  3 +++
 2 files changed, 27 insertions(+), 17 deletions(-)

Comments

Ben Pfaff Aug. 29, 2019, 2:37 p.m. UTC | #1
On Tue, Aug 27, 2019 at 04:59:02PM -0700, Darrell Ball wrote:
> The ICMPv4 error data L4 length check was found to be too strict for TCP,
> expecting a minimum of 20 rather than 8 bytes.  This worked by
> hapenstance for other inner protocols.  The approach is to explicitly
> handle the ICMPv4 error data L4 length check and to do this for all
> supported inner protocols in the same way.  Making the code common
> between protocols also allows the existing ICMPv4 related UDP tests to
> cover TCP and ICMP inner protocol cases.
> Note that ICMPv6 does not have an 8 byte limit for error L4 data.
> 
> Fixes: a489b16854b5 ("conntrack: New userspace connection tracker.")
> CC: Daniele Di Proietto <diproiettod@ovn.org>
> Reported-at: https://mail.openvswitch.org/pipermail/ovs-dev/2019-August/361949.html
> Reported-by: Vishal Deep Ajmera <vishal.deep.ajmera@ericsson.com>
> Signed-off-by: Vishal Deep Ajmera <vishal.deep.ajmera@ericsson.com>
> Co-authored-by: Vishal Deep Ajmera <vishal.deep.ajmera@ericsson.com>
> Signed-off-by: Darrell Ball <dlu998@gmail.com>

Thanks, applied to master and branch-2.12.
Darrell Ball Aug. 29, 2019, 4:56 p.m. UTC | #2
On Thu, Aug 29, 2019 at 7:37 AM Ben Pfaff <blp@ovn.org> wrote:

> On Tue, Aug 27, 2019 at 04:59:02PM -0700, Darrell Ball wrote:
> > The ICMPv4 error data L4 length check was found to be too strict for TCP,
> > expecting a minimum of 20 rather than 8 bytes.  This worked by
> > hapenstance for other inner protocols.  The approach is to explicitly
> > handle the ICMPv4 error data L4 length check and to do this for all
> > supported inner protocols in the same way.  Making the code common
> > between protocols also allows the existing ICMPv4 related UDP tests to
> > cover TCP and ICMP inner protocol cases.
> > Note that ICMPv6 does not have an 8 byte limit for error L4 data.
> >
> > Fixes: a489b16854b5 ("conntrack: New userspace connection tracker.")
> > CC: Daniele Di Proietto <diproiettod@ovn.org>
> > Reported-at:
> https://mail.openvswitch.org/pipermail/ovs-dev/2019-August/361949.html
> > Reported-by: Vishal Deep Ajmera <vishal.deep.ajmera@ericsson.com>
> > Signed-off-by: Vishal Deep Ajmera <vishal.deep.ajmera@ericsson.com>
> > Co-authored-by: Vishal Deep Ajmera <vishal.deep.ajmera@ericsson.com>
> > Signed-off-by: Darrell Ball <dlu998@gmail.com>
>
> Thanks, applied to master and branch-2.12.
>

Thanks
This is eligible to go back to 2.6; it should apply cleanly back to 2.9; I
can look into the remaining ones,
unless Vishal would like to do those.
Vishal Deep Ajmera via dev Sept. 23, 2019, 6:58 a.m. UTC | #3
> 
> Thanks
> This is eligible to go back to 2.6; it should apply cleanly back to 2.9; I
> can look into the remaining ones,
> unless Vishal would like to do those.

Thanks Darrell. I have sent patches for branch 2.8 and 2.9.
For branches before 2.7 & 2.6 it is giving quite a few conflicts.
Can you please have a look at it?

Hi Ben, 

Can you please apply the patch on branch 2.10 & 2.11. It should apply
cleanly on them.

Warm Regards,
Vishal Ajmera

Patch
diff mbox series

diff --git a/lib/conntrack.c b/lib/conntrack.c
index 5f60fea..e5266e5 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -1514,9 +1514,10 @@  check_l4_icmp6(const struct conn_key *key, const void *data, size_t size,
 }
 
 static inline bool
-extract_l4_tcp(struct conn_key *key, const void *data, size_t size)
+extract_l4_tcp(struct conn_key *key, const void *data, size_t size,
+               size_t *chk_len)
 {
-    if (OVS_UNLIKELY(size < TCP_HEADER_LEN)) {
+    if (OVS_UNLIKELY(size < (chk_len ? *chk_len : TCP_HEADER_LEN))) {
         return false;
     }
 
@@ -1529,9 +1530,10 @@  extract_l4_tcp(struct conn_key *key, const void *data, size_t size)
 }
 
 static inline bool
-extract_l4_udp(struct conn_key *key, const void *data, size_t size)
+extract_l4_udp(struct conn_key *key, const void *data, size_t size,
+               size_t *chk_len)
 {
-    if (OVS_UNLIKELY(size < UDP_HEADER_LEN)) {
+    if (OVS_UNLIKELY(size < (chk_len ? *chk_len : UDP_HEADER_LEN))) {
         return false;
     }
 
@@ -1545,7 +1547,7 @@  extract_l4_udp(struct conn_key *key, const void *data, size_t size)
 
 static inline bool extract_l4(struct conn_key *key, const void *data,
                               size_t size, bool *related, const void *l3,
-                              bool validate_checksum);
+                              bool validate_checksum, size_t *chk_len);
 
 static uint8_t
 reverse_icmp_type(uint8_t type)
@@ -1577,9 +1579,9 @@  reverse_icmp_type(uint8_t type)
  * possible */
 static inline int
 extract_l4_icmp(struct conn_key *key, const void *data, size_t size,
-                bool *related)
+                bool *related, size_t *chk_len)
 {
-    if (OVS_UNLIKELY(size < ICMP_HEADER_LEN)) {
+    if (OVS_UNLIKELY(size < (chk_len ? *chk_len : ICMP_HEADER_LEN))) {
         return false;
     }
 
@@ -1630,8 +1632,9 @@  extract_l4_icmp(struct conn_key *key, const void *data, size_t size,
         key->src = inner_key.src;
         key->dst = inner_key.dst;
         key->nw_proto = inner_key.nw_proto;
+        size_t check_len = ICMP_ERROR_DATA_L4_LEN;
 
-        ok = extract_l4(key, l4, tail - l4, NULL, l3, false);
+        ok = extract_l4(key, l4, tail - l4, NULL, l3, false, &check_len);
         if (ok) {
             conn_key_reverse(key);
             *related = true;
@@ -1718,7 +1721,7 @@  extract_l4_icmp6(struct conn_key *key, const void *data, size_t size,
         key->dst = inner_key.dst;
         key->nw_proto = inner_key.nw_proto;
 
-        ok = extract_l4(key, l4, tail - l4, NULL, l3, false);
+        ok = extract_l4(key, l4, tail - l4, NULL, l3, false, NULL);
         if (ok) {
             conn_key_reverse(key);
             *related = true;
@@ -1743,26 +1746,29 @@  extract_l4_icmp6(struct conn_key *key, const void *data, size_t size,
  * an ICMP or ICMP6 header.
  *
  * If 'related' is NULL, it means that we're already parsing a header nested
- * in an ICMP error.  In this case, we skip checksum and length validation. */
+ * in an ICMP error.  In this case, we skip the checksum and some length
+ * validations. */
 static inline bool
 extract_l4(struct conn_key *key, const void *data, size_t size, bool *related,
-           const void *l3, bool validate_checksum)
+           const void *l3, bool validate_checksum, size_t *chk_len)
 {
     if (key->nw_proto == IPPROTO_TCP) {
         return (!related || check_l4_tcp(key, data, size, l3,
-                validate_checksum)) && extract_l4_tcp(key, data, size);
+                validate_checksum))
+               && extract_l4_tcp(key, data, size, chk_len);
     } else if (key->nw_proto == IPPROTO_UDP) {
         return (!related || check_l4_udp(key, data, size, l3,
-                validate_checksum)) && extract_l4_udp(key, data, size);
+                validate_checksum))
+               && extract_l4_udp(key, data, size, chk_len);
     } else if (key->dl_type == htons(ETH_TYPE_IP)
                && key->nw_proto == IPPROTO_ICMP) {
         return (!related || check_l4_icmp(data, size, validate_checksum))
-               && extract_l4_icmp(key, data, size, related);
+               && extract_l4_icmp(key, data, size, related, chk_len);
     } else if (key->dl_type == htons(ETH_TYPE_IPV6)
                && key->nw_proto == IPPROTO_ICMPV6) {
         return (!related || check_l4_icmp6(key, data, size, l3,
-                validate_checksum)) && extract_l4_icmp6(key, data, size,
-                related);
+                validate_checksum))
+               && extract_l4_icmp6(key, data, size, related);
     } else {
         return false;
     }
@@ -1841,7 +1847,8 @@  conn_key_extract(struct conntrack *ct, struct dp_packet *pkt, ovs_be16 dl_type,
             bool  hwol_good_l4_csum = dp_packet_l4_checksum_valid(pkt);
             /* Validate the checksum only when hwol is not supported. */
             if (extract_l4(&ctx->key, l4, dp_packet_l4_size(pkt),
-                           &ctx->icmp_related, l3, !hwol_good_l4_csum)) {
+                           &ctx->icmp_related, l3, !hwol_good_l4_csum,
+                           NULL)) {
                 ctx->hash = conn_key_hash(&ctx->key, ct->hash_basis);
                 return true;
             }
diff --git a/lib/packets.h b/lib/packets.h
index a4bee38..c440098 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -769,6 +769,9 @@  struct icmp_header {
 };
 BUILD_ASSERT_DECL(ICMP_HEADER_LEN == sizeof(struct icmp_header));
 
+/* ICMPV4 */
+#define ICMP_ERROR_DATA_L4_LEN 8
+
 #define IGMP_HEADER_LEN 8
 struct igmp_header {
     uint8_t igmp_type;