diff mbox series

[ovs-dev,1/6] conntrack: fix multiple tcp seq adjustments

Message ID 1544895448-14499-2-git-send-email-david.marchand@redhat.com
State Changes Requested, archived
Headers show
Series fixes for ftp alg in userspace dp | expand

Commit Message

David Marchand Dec. 15, 2018, 5:37 p.m. UTC
The ftp alg deals with packets in two ways for the command connection:
either they are inspected (CT_FTP_CTL_INTEREST) or they just go through
without being modified (CT_FTP_CTL_OTHER).

In both cases, the tcp seq/ack must be adjusted by the current offset
that has been introduced in previous mangle operations and prepare for
the next packets by setting an accumulated offset.

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 lib/conntrack.c | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

Comments

Darrell Ball Dec. 19, 2018, 8:16 a.m. UTC | #1
Thanks for working on this.

1/
What is the use case for multiple adjustments?
This code has been tested externally to Vmware as well.
Also multiple adjustments may be indicative of an exploit attempt or other
problem, so lets delineate
the use case first; please add a 'real' test case for this.

2/
IF we end up supporting multiple adjustments, as it stands now the patch
fails these tests
conntrack - NAT

 96: conntrack - FTP NAT postrecirc seqadj           FAILED (
system-traffic.at:4391)
 98: conntrack - FTP NAT orig tuple seqadj           FAILED (
system-traffic.at:4515)

The following alternative patch would correctly and succinctly implement
multiple adjustments.

diff --git a/lib/conntrack.c b/lib/conntrack.c
index 6f6021a..f283db2 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -3225,7 +3225,8 @@ handle_ftp_ctl(struct conntrack *ct, const struct
conn_lookup_ctx *ctx,
                     ip_len += seq_skew;
                     nh6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(ip_len);
                     conn_seq_skew_set(ct, &conn_for_expectation->key, now,
-                                      seq_skew, ctx->reply);
+                                      seq_skew +
+                                      conn_for_expectation->seq_skew,
ctx->reply);
                 }
             } else {
                 seq_skew = repl_ftp_v4_addr(pkt, v4_addr_rep,
ftp_data_start,
@@ -3237,7 +3238,8 @@ handle_ftp_ctl(struct conntrack *ct, const struct
conn_lookup_ctx *ctx,
                                           l3_hdr->ip_tot_len,
htons(ip_len));
                     l3_hdr->ip_tot_len = htons(ip_len);
                     conn_seq_skew_set(ct, &conn_for_expectation->key, now,
-                                      seq_skew, ctx->reply);
+                                      seq_skew +
+                                      conn_for_expectation->seq_skew,
ctx->reply);
                 }
             }
         } else {





On Sat, Dec 15, 2018 at 9:38 AM David Marchand <david.marchand@redhat.com>
wrote:

> The ftp alg deals with packets in two ways for the command connection:
> either they are inspected (CT_FTP_CTL_INTEREST) or they just go through
> without being modified (CT_FTP_CTL_OTHER).
>
> In both cases, the tcp seq/ack must be adjusted by the current offset
> that has been introduced in previous mangle operations and prepare for
> the next packets by setting an accumulated offset.
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
>  lib/conntrack.c | 25 ++++++++++++-------------
>  1 file changed, 12 insertions(+), 13 deletions(-)
>
> diff --git a/lib/conntrack.c b/lib/conntrack.c
> index 974f985..d08d0ea 100644
> --- a/lib/conntrack.c
> +++ b/lib/conntrack.c
> @@ -3185,11 +3185,9 @@ handle_ftp_ctl(struct conntrack *ct, const struct
> conn_lookup_ctx *ctx,
>      }
>
>      struct ovs_16aligned_ip6_hdr *nh6 = dp_packet_l3(pkt);
> -    int64_t seq_skew = 0;
> +    int64_t seq_skew = conn_for_expectation->seq_skew;
>
> -    if (ftp_ctl == CT_FTP_CTL_OTHER) {
> -        seq_skew = conn_for_expectation->seq_skew;
> -    } else if (ftp_ctl == CT_FTP_CTL_INTEREST) {
> +    if (ftp_ctl == CT_FTP_CTL_INTEREST) {
>          enum ftp_ctl_pkt rc;
>          if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) {
>              rc = process_ftp_ctl_v6(ct, pkt, conn_for_expectation,
> @@ -3208,35 +3206,36 @@ handle_ftp_ctl(struct conntrack *ct, const struct
> conn_lookup_ctx *ctx,
>              return;
>          } else if (rc == CT_FTP_CTL_INTEREST) {
>              uint16_t ip_len;
> +            int64_t new_skew;
>
>              if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) {
> -                seq_skew = repl_ftp_v6_addr(pkt, v6_addr_rep,
> ftp_data_start,
> +                new_skew = repl_ftp_v6_addr(pkt, v6_addr_rep,
> ftp_data_start,
>
>  addr_offset_from_ftp_data_start,
>                                              addr_size, mode);
> -                if (seq_skew) {
> +                if (new_skew) {
>                      ip_len = ntohs(nh6->ip6_ctlun.ip6_un1.ip6_un1_plen);
> -                    ip_len += seq_skew;
> +                    ip_len += new_skew;
>                      nh6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(ip_len);
>                      conn_seq_skew_set(ct, &conn_for_expectation->key, now,
> -                                      seq_skew, ctx->reply);
> +                                      new_skew + seq_skew, ctx->reply);
>                  }
>              } else {
> -                seq_skew = repl_ftp_v4_addr(pkt, v4_addr_rep,
> ftp_data_start,
> +                new_skew = repl_ftp_v4_addr(pkt, v4_addr_rep,
> ftp_data_start,
>
>  addr_offset_from_ftp_data_start);
>                  ip_len = ntohs(l3_hdr->ip_tot_len);
> -                if (seq_skew) {
> -                    ip_len += seq_skew;
> +                if (new_skew) {
> +                    ip_len += new_skew;
>                      l3_hdr->ip_csum = recalc_csum16(l3_hdr->ip_csum,
>                                            l3_hdr->ip_tot_len,
> htons(ip_len));
>                      l3_hdr->ip_tot_len = htons(ip_len);
>                      conn_seq_skew_set(ct, &conn_for_expectation->key, now,
> -                                      seq_skew, ctx->reply);
> +                                      new_skew + seq_skew, ctx->reply);
>                  }
>              }
>          } else {
>              OVS_NOT_REACHED();
>          }
> -    } else {
> +    } else if (ftp_ctl == CT_FTP_CTL_INVALID) {
>          OVS_NOT_REACHED();
>      }
>
> --
> 1.8.3.1
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
David Marchand Dec. 19, 2018, 8:57 a.m. UTC | #2
Hello Darrell,

On Wed, Dec 19, 2018 at 9:16 AM Darrell Ball <dlu998@gmail.com> wrote:

> 1/
> What is the use case for multiple adjustments?
> This code has been tested externally to Vmware as well.
> Also multiple adjustments may be indicative of an exploit attempt or other
> problem, so lets delineate
> the use case first; please add a 'real' test case for this.
>

Connect a ftp client to a server with nat (with the nat triggering a tcp
seq ajustement), then enter several commands and watch the tcp seq numbers
on the command connection.
See patch 5 for the test, I put it later in the series to avoid test
failures.


> 2/
> IF we end up supporting multiple adjustments, as it stands now the patch
> fails these tests
> conntrack - NAT
>
>  96: conntrack - FTP NAT postrecirc seqadj           FAILED (
> system-traffic.at:4391)
>  98: conntrack - FTP NAT orig tuple seqadj           FAILED (
> system-traffic.at:4515)
>

Argh, indeed, I guess patch 2 should come first, will check.
Darrell Ball Dec. 19, 2018, 9:05 a.m. UTC | #3
On Wed, Dec 19, 2018 at 12:57 AM David Marchand <david.marchand@redhat.com>
wrote:

> Hello Darrell,
>
> On Wed, Dec 19, 2018 at 9:16 AM Darrell Ball <dlu998@gmail.com> wrote:
>
>> 1/
>> What is the use case for multiple adjustments?
>> This code has been tested externally to Vmware as well.
>> Also multiple adjustments may be indicative of an exploit attempt or
>> other problem, so lets delineate
>> the use case first; please add a 'real' test case for this.
>>
>
> Connect a ftp client to a server with nat (with the nat triggering a tcp
> seq ajustement), then enter several commands and watch the tcp seq numbers
> on the command connection.
> See patch 5 for the test, I put it later in the series to avoid test
> failures.
>

fold patch 5 into patch 1 and I'll take another look.



>
>
>> 2/
>> IF we end up supporting multiple adjustments, as it stands now the patch
>> fails these tests
>> conntrack - NAT
>>
>>  96: conntrack - FTP NAT postrecirc seqadj           FAILED (
>> system-traffic.at:4391)
>>  98: conntrack - FTP NAT orig tuple seqadj           FAILED (
>> system-traffic.at:4515)
>>
>
> Argh, indeed, I guess patch 2 should come first, will check.
>

I am not sure Patch 2 is needed at all; it breaks the common code path
intent as well.


>
>
> --
> David Marchand
>
diff mbox series

Patch

diff --git a/lib/conntrack.c b/lib/conntrack.c
index 974f985..d08d0ea 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -3185,11 +3185,9 @@  handle_ftp_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
     }
 
     struct ovs_16aligned_ip6_hdr *nh6 = dp_packet_l3(pkt);
-    int64_t seq_skew = 0;
+    int64_t seq_skew = conn_for_expectation->seq_skew;
 
-    if (ftp_ctl == CT_FTP_CTL_OTHER) {
-        seq_skew = conn_for_expectation->seq_skew;
-    } else if (ftp_ctl == CT_FTP_CTL_INTEREST) {
+    if (ftp_ctl == CT_FTP_CTL_INTEREST) {
         enum ftp_ctl_pkt rc;
         if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) {
             rc = process_ftp_ctl_v6(ct, pkt, conn_for_expectation,
@@ -3208,35 +3206,36 @@  handle_ftp_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
             return;
         } else if (rc == CT_FTP_CTL_INTEREST) {
             uint16_t ip_len;
+            int64_t new_skew;
 
             if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) {
-                seq_skew = repl_ftp_v6_addr(pkt, v6_addr_rep, ftp_data_start,
+                new_skew = repl_ftp_v6_addr(pkt, v6_addr_rep, ftp_data_start,
                                             addr_offset_from_ftp_data_start,
                                             addr_size, mode);
-                if (seq_skew) {
+                if (new_skew) {
                     ip_len = ntohs(nh6->ip6_ctlun.ip6_un1.ip6_un1_plen);
-                    ip_len += seq_skew;
+                    ip_len += new_skew;
                     nh6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(ip_len);
                     conn_seq_skew_set(ct, &conn_for_expectation->key, now,
-                                      seq_skew, ctx->reply);
+                                      new_skew + seq_skew, ctx->reply);
                 }
             } else {
-                seq_skew = repl_ftp_v4_addr(pkt, v4_addr_rep, ftp_data_start,
+                new_skew = repl_ftp_v4_addr(pkt, v4_addr_rep, ftp_data_start,
                                             addr_offset_from_ftp_data_start);
                 ip_len = ntohs(l3_hdr->ip_tot_len);
-                if (seq_skew) {
-                    ip_len += seq_skew;
+                if (new_skew) {
+                    ip_len += new_skew;
                     l3_hdr->ip_csum = recalc_csum16(l3_hdr->ip_csum,
                                           l3_hdr->ip_tot_len, htons(ip_len));
                     l3_hdr->ip_tot_len = htons(ip_len);
                     conn_seq_skew_set(ct, &conn_for_expectation->key, now,
-                                      seq_skew, ctx->reply);
+                                      new_skew + seq_skew, ctx->reply);
                 }
             }
         } else {
             OVS_NOT_REACHED();
         }
-    } else {
+    } else if (ftp_ctl == CT_FTP_CTL_INVALID) {
         OVS_NOT_REACHED();
     }