From 5db228b9f6ece9ace59b42431b68b641a495a3d1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 11 Apr 2014 17:31:46 +0200 Subject: [PATCH] stream: fix raw reassembly flag issue AppLayer reassembly correctly only flags a segment as done when it's completely used in reassembly. Raw reassembly could flag a partially used segment as complete as well. In this case the segment could be discarded early. Further reassembly would miss data, leading to a gap. Due to this, up to 'window size' bytes worth of segments could remain in the session for a long time, leading to memory resource pressure. This patch sets the flag correctly. --- src/stream-tcp-reassemble.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 105e5d042d..5b34f8524e 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -3221,8 +3221,10 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSegment *next_seg = seg->next; next_seq = seg->seq + seg->payload_len; if (partial == FALSE) { - SCLogDebug("fully done with segment in app layer reassembly"); + SCLogDebug("fully done with segment in app layer reassembly (seg %p seq %"PRIu32")", + seg, seg->seq); seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED; + SCLogDebug("flags now %02x", seg->flags); } else { SCLogDebug("not yet fully done with segment in app layer reassembly"); } @@ -3300,9 +3302,9 @@ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, /* loop through the segments and fill one or more msgs */ for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);) { - SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32, + SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32", flags %02x", seg, seg->seq, seg->payload_len, - (uint32_t)(seg->seq + seg->payload_len)); + (uint32_t)(seg->seq + seg->payload_len), seg->flags); if ((p->flow->flags & FLOW_NO_APPLAYER_INSPECTION) || (stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) || @@ -3405,6 +3407,8 @@ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, } } + int partial = FALSE; + /* if the segment ends beyond ra_base_seq we need to consider it */ if (SEQ_GT((seg->seq + seg->payload_len), ra_base_seq+1)) { SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " @@ -3422,6 +3426,7 @@ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, } else { payload_len = (stream->last_ack - seg->seq) - payload_offset; } + partial = TRUE; } else { payload_len = seg->payload_len - payload_offset; } @@ -3435,6 +3440,7 @@ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { payload_len = stream->last_ack - seg->seq; + partial = TRUE; } else { payload_len = seg->payload_len; } @@ -3564,8 +3570,15 @@ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, /* done with this segment, return it to the pool */ TcpSegment *next_seg = seg->next; - seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED; next_seq = seg->seq + seg->payload_len; + if (partial == FALSE) { + SCLogDebug("fully done with segment in raw reassembly (seg %p seq %"PRIu32")", + seg, seg->seq); + seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED; + SCLogDebug("flags now %02x", seg->flags); + } else { + SCLogDebug("not yet fully done with segment in raw reassembly"); + } seg = next_seg; }