Fix a issue in stream reassembly causing the segment list getting into a inconsistent state.

remotes/origin/master-1.1.x
Victor Julien 15 years ago
parent 4e9231266a
commit b233105cc2

@ -423,20 +423,20 @@ void PrintList2(TcpSegment *seg)
* a hack though, we're going to check next how we end up with
* a segment list with seq differences that big */
if (!(SEQ_LT(seg->prev->seq,seg->seq))) {
SCLogDebug("inconsistant list: SEQ_LT(seg->seq,seg->prev->seq)) =="
SCLogDebug("inconsistent list: SEQ_LT(seg->seq,seg->prev->seq)) =="
" TRUE, seg->seq %" PRIu32 ", seg->prev->seq %" PRIu32 ""
"", seg->seq, seg->prev->seq);
}
}
if (SEQ_LT(seg->seq,next_seq)) {
SCLogDebug("inconsistant list: SEQ_LT(seg->seq,next_seq)) == TRUE, "
SCLogDebug("inconsistent list: SEQ_LT(seg->seq,next_seq)) == TRUE, "
"seg->seq %" PRIu32 ", next_seq %" PRIu32 "", seg->seq,
next_seq);
}
if (prev_seg != seg->prev) {
SCLogDebug("inconsistant list: prev_seg %p != seg->prev %p",
SCLogDebug("inconsistent list: prev_seg %p != seg->prev %p",
prev_seg, seg->prev);
}
@ -472,7 +472,7 @@ void PrintList(TcpSegment *seg)
* a hack though, we're going to check next how we end up with
* a segment list with seq differences that big */
if (!(SEQ_LT(seg->prev->seq,seg->seq))) {
SCLogDebug("inconsistant list: SEQ_LT(seg->seq,seg->prev->seq)) == "
SCLogDebug("inconsistent list: SEQ_LT(seg->seq,seg->prev->seq)) == "
"TRUE, seg->seq %" PRIu32 ", seg->prev->seq %" PRIu32 "",
seg->seq, seg->prev->seq);
PrintList2(head_seg);
@ -481,7 +481,7 @@ void PrintList(TcpSegment *seg)
}
if (SEQ_LT(seg->seq,next_seq)) {
SCLogDebug("inconsistant list: SEQ_LT(seg->seq,next_seq)) == TRUE, "
SCLogDebug("inconsistent list: SEQ_LT(seg->seq,next_seq)) == TRUE, "
"seg->seq %" PRIu32 ", next_seq %" PRIu32 "", seg->seq,
next_seq);
PrintList2(head_seg);
@ -489,7 +489,7 @@ void PrintList(TcpSegment *seg)
}
if (prev_seg != seg->prev) {
SCLogDebug("inconsistant list: prev_seg %p != seg->prev %p",
SCLogDebug("inconsistent list: prev_seg %p != seg->prev %p",
prev_seg, seg->prev);
PrintList2(head_seg);
abort();
@ -559,8 +559,8 @@ int StreamTcpReassembleInsertSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_
goto end;
}
SCLogDebug("SEQ+payload %"PRIu32", last_ack %"PRIu32", "
"ra_app_base_seq %"PRIu32, (TCP_GET_SEQ(p)+p->payload_len),
SCLogDebug("SEQ %"PRIu32", SEQ+payload %"PRIu32", last_ack %"PRIu32", "
"ra_app_base_seq %"PRIu32, TCP_GET_SEQ(p), (TCP_GET_SEQ(p)+p->payload_len),
stream->last_ack, stream->ra_app_base_seq);
/* fast track */
@ -663,6 +663,7 @@ int StreamTcpReassembleInsertSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_
if (list_seg->next == NULL) {
list_seg->next = seg;
seg->prev = list_seg;
stream->seg_list_tail = seg;
goto end;
}
} else {
@ -724,6 +725,7 @@ static int HandleSegmentStartsBeforeListSegment(ThreadVars *tv, TcpReassemblyThr
#ifdef DEBUG
SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 "", seg->seq,
seg->payload_len);
PrintList(stream->seg_list);
#endif
if (SEQ_GT((seg->seq + seg->payload_len), list_seg->seq) &&
@ -774,6 +776,47 @@ static int HandleSegmentStartsBeforeListSegment(ThreadVars *tv, TcpReassemblyThr
}
if (overlap > 0) {
/* handle the case where we need to fill a gap before list_seg first */
if (list_seg->prev != NULL && SEQ_LT((list_seg->prev->seq + list_seg->prev->payload_len), list_seg->seq)) {
SCLogDebug("GAP to fill before list segment, size %u", list_seg->seq - (list_seg->prev->seq + list_seg->prev->payload_len));
uint32_t new_seq = (list_seg->prev->seq + list_seg->prev->payload_len);
if (SEQ_GT(seg->seq, new_seq)) {
new_seq = seg->seq;
}
packet_length = list_seg->seq - new_seq;
if (packet_length > seg->payload_len) {
packet_length = seg->payload_len;
}
TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
if (new_seg == NULL) {
SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
SCReturnInt(-1);
}
new_seg->payload_len = packet_length;
new_seg->seq = new_seq;
SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len "
"%" PRIu16"", new_seg->seq, new_seg->payload_len);
new_seg->next = list_seg;
new_seg->prev = list_seg->prev;
list_seg->prev->next = new_seg;
list_seg->prev = new_seg;
/* create a new seg, copy the list_seg data over */
StreamTcpSegmentDataCopy(new_seg, seg);
#ifdef DEBUG
PrintList(stream->seg_list);
#endif
}
/* Handling case when the segment starts before the first segment in
* the list */
if (list_seg->prev == NULL) {
@ -837,6 +880,7 @@ static int HandleSegmentStartsBeforeListSegment(ThreadVars *tv, TcpReassemblyThr
stream->seg_list = new_seg;
SCLogDebug("list_seg now %p, stream->seg_list now %p", list_seg,
stream->seg_list);
} else if (end_before == TRUE || end_same == TRUE) {
/* Handling overlapping with more than one segment and filling gap */
if (SEQ_GT(list_seg->seq, (list_seg->prev->seq +
@ -897,48 +941,6 @@ static int HandleSegmentStartsBeforeListSegment(ThreadVars *tv, TcpReassemblyThr
}
}
} else if (end_after == TRUE) {
if (list_seg->prev != NULL && SEQ_LT((list_seg->prev->seq + list_seg->prev->payload_len), list_seg->seq)) {
SCLogDebug("GAP to fill before list segment, size %u", list_seg->seq - (list_seg->prev->seq + list_seg->prev->payload_len));
packet_length = list_seg->seq - seg->seq;
if (packet_length > seg->payload_len) {
packet_length = seg->payload_len;
}
TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
if (new_seg == NULL) {
SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
SCReturnInt(-1);
}
new_seg->payload_len = packet_length;
if (SEQ_GT((list_seg->prev->seq +
list_seg->prev->payload_len), seg->seq))
{
new_seg->seq = (list_seg->prev->seq +
list_seg->prev->payload_len);
} else {
new_seg->seq = seg->seq;
}
SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len "
"%" PRIu16"", new_seg->seq, new_seg->payload_len);
new_seg->next = list_seg;
new_seg->prev = list_seg->prev;
list_seg->prev->next = new_seg;
list_seg->prev = new_seg;
/* create a new seg, copy the list_seg data over */
StreamTcpSegmentDataCopy(new_seg, seg);
#ifdef DEBUG
PrintList(stream->seg_list);
#endif
}
if (list_seg->next != NULL) {
if (SEQ_LEQ((seg->seq + seg->payload_len), list_seg->next->seq))
{
@ -1121,7 +1123,7 @@ static int HandleSegmentStartsBeforeListSegment(ThreadVars *tv, TcpReassemblyThr
}
}
/* To return from for loop as seg is finished with current list_seg
no need to check further (improve performance)*/
no need to check further (improve performance) */
if (end_before == TRUE || end_same == TRUE || return_after == TRUE) {
SCReturnInt(1);
}
@ -3587,20 +3589,26 @@ void StreamTcpSegmentDataReplace(TcpSegment *dst_seg, TcpSegment *src_seg,
void StreamTcpSegmentDataCopy(TcpSegment *dst_seg, TcpSegment *src_seg)
{
uint32_t i;
uint32_t u;
uint16_t dst_pos = 0;
uint16_t src_pos = 0;
uint32_t seq;
if (SEQ_GT(src_seg->seq, dst_seg->seq))
if (SEQ_GT(dst_seg->seq, src_seg->seq)) {
src_pos = dst_seg->seq - src_seg->seq;
seq = dst_seg->seq;
} else {
dst_pos = src_seg->seq - dst_seg->seq;
else
dst_pos = dst_seg->seq - src_seg->seq;
seq = src_seg->seq;
}
SCLogDebug("Copying data from dst_pos %"PRIu16"", dst_pos);
for (i = src_seg->seq;
(SEQ_LT(i, (src_seg->seq + src_seg->payload_len)) &&
SEQ_LT(i, (dst_seg->seq + dst_seg->payload_len))); i++)
SCLogDebug("Copying data from seq %"PRIu32"", seq);
for (u = seq;
(SEQ_LT(u, (src_seg->seq + src_seg->payload_len)) &&
SEQ_LT(u, (dst_seg->seq + dst_seg->payload_len))); u++)
{
//SCLogDebug("u %"PRIu32, u);
dst_seg->payload[dst_pos] = src_seg->payload[src_pos];
dst_pos++;
@ -8963,6 +8971,90 @@ end:
return ret;
}
/** \test test insert with overlaps
*/
static int StreamTcpReassembleInsertTest02(void) {
int ret = 0;
TcpReassemblyThreadCtx *ra_ctx = NULL;
ThreadVars tv;
TcpSession ssn;
memset(&tv, 0x00, sizeof(tv));
StreamTcpUTInit(&ra_ctx);
StreamTcpUTSetupSession(&ssn);
StreamTcpUTSetupStream(&ssn.client, 1);
int i;
for (i = 2; i < 10; i++) {
int len;
len = i % 2;
if (len == 0)
len = 1;
int seq;
seq = i * 10;
if (seq < 2)
seq = 2;
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'A', len) == -1) {
printf("failed to add segment 1: ");
goto end;
}
}
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'B', 1024) == -1) {
printf("failed to add segment 2: ");
goto end;
}
ret = 1;
end:
StreamTcpUTClearSession(&ssn);
StreamTcpUTDeinit(ra_ctx);
return ret;
}
/** \test test insert with overlaps
*/
static int StreamTcpReassembleInsertTest03(void) {
int ret = 0;
TcpReassemblyThreadCtx *ra_ctx = NULL;
ThreadVars tv;
TcpSession ssn;
memset(&tv, 0x00, sizeof(tv));
StreamTcpUTInit(&ra_ctx);
StreamTcpUTSetupSession(&ssn);
StreamTcpUTSetupStream(&ssn.client, 1);
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 1024) == -1) {
printf("failed to add segment 2: ");
goto end;
}
int i;
for (i = 2; i < 10; i++) {
int len;
len = i % 2;
if (len == 0)
len = 1;
int seq;
seq = i * 10;
if (seq < 2)
seq = 2;
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'B', len) == -1) {
printf("failed to add segment 2: ");
goto end;
}
}
ret = 1;
end:
StreamTcpUTClearSession(&ssn);
StreamTcpUTDeinit(ra_ctx);
return ret;
}
#endif /* UNITTESTS */
/** \brief The Function Register the Unit tests to test the reassembly engine
@ -9032,6 +9124,8 @@ void StreamTcpReassembleRegisterTests(void) {
UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10", StreamTcpReassembleInlineTest10, 1);
UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap", StreamTcpReassembleInsertTest01, 1);
UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap", StreamTcpReassembleInsertTest02, 1);
UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap", StreamTcpReassembleInsertTest03, 1);
StreamTcpInlineRegisterTests();
StreamTcpUtilRegisterTests();

Loading…
Cancel
Save