From 7438f981dae92e3e29f00abb5e0fdb80e08c39e2 Mon Sep 17 00:00:00 2001 From: Gurvinder Singh Date: Sun, 21 Mar 2010 18:09:27 +0100 Subject: [PATCH] stream memory leaks fixed and unit tests added --- src/stream-tcp-reassemble.c | 71 +++++++++++++ src/stream-tcp.c | 169 +++++++++++++++++++++++++++++++ src/util-classification-config.c | 10 ++ 3 files changed, 250 insertions(+) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 7b48fe397b..3f0e5f94b1 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -726,6 +726,71 @@ static int HandleSegmentStartsBeforeListSegment(TcpStream *stream, list_seg = new_seg; return_after = TRUE; } + /* Handle the case, when list_seg is the end of segment list, but + seg is ending after the list_seg. So we need to copy the data + from newly received segment. After copying return the newly + received seg to pool */ + } else { + if (SEQ_GT(seg->seq, (list_seg->prev->seq + + list_seg->prev->payload_len))) + { + packet_length = list_seg->payload_len + (list_seg->seq - + seg->seq); + } else { + packet_length = list_seg->payload_len + (list_seg->seq - + (list_seg->prev->seq + + list_seg->prev->payload_len)); + } + + packet_length += (seg->seq + seg->payload_len) - + (list_seg->seq + list_seg->payload_len); + + TcpSegment *new_seg = StreamTcpGetSegment(packet_length); + if (new_seg == NULL) { + SCLogDebug("segment_pool[%"PRIu16"] is empty", + segment_pool_idx[packet_length]); + 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->next; + new_seg->prev = list_seg->prev; + + /* create a new seg, copy the list_seg data over */ + StreamTcpSegmentDataCopy(new_seg, list_seg); + + /* copy the part before list_seg */ + uint16_t copy_len = list_seg->seq - new_seg->seq; + StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq, + copy_len); + + /* copy the part after list_seg */ + copy_len = (seg->seq + seg->payload_len) - + (list_seg->seq + list_seg->payload_len); + StreamTcpSegmentDataReplace(new_seg, seg, (list_seg->seq + + list_seg->payload_len), copy_len); + + if (new_seg->prev != NULL) { + new_seg->prev->next = new_seg; + } + + /*update the stream last_seg in case of removal of list_seg*/ + if (stream->seg_list_tail == list_seg) + stream->seg_list_tail = new_seg; + + StreamTcpSegmentReturntoPool(list_seg); + list_seg = new_seg; + return_after = TRUE; } } @@ -865,6 +930,12 @@ static int HandleSegmentStartsAtSameListSegment(TcpStream *stream, { handle_beyond = TRUE; } + /* Handle the case, when list_seg is the end of segment list, but + seg is ending after the list_seg. So we need to copy the data + from newly received segment. After copying return the newly + received seg to pool */ + } else { + fill_gap = TRUE; } SCLogDebug("fill_gap %s, handle_beyond %s", fill_gap?"TRUE":"FALSE", diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 8ba3e5d418..b4d00ee072 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -5135,6 +5135,173 @@ end: ConfRestoreContextBackup(); return ret; } + +/** \test Test the stream mem leaks conditions. */ +static int StreamTcpTest23(void) +{ + TcpSession ssn; + Packet p; + Flow f; + TCPHdr tcph; + TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); + TcpStream stream; + memset(&stream, 0, sizeof (TcpStream)); + stream.os_policy = OS_POLICY_BSD; + uint8_t packet[1460] = ""; + int result = 1; + + StreamTcpInitConfig(TRUE); + + /* prevent L7 from kicking in */ + StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOSERVER, 4096); + StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOCLIENT, 4096); + StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); + StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); + + memset(&ssn, 0, sizeof (TcpSession)); + memset(&p, 0, sizeof (Packet)); + memset(&f, 0, sizeof (Flow)); + memset(&tcph, 0, sizeof (TCPHdr)); + f.protoctx = &ssn; + p.src.family = AF_INET; + p.dst.family = AF_INET; + p.proto = IPPROTO_TCP; + p.flow = &f; + tcph.th_win = 5480; + tcph.th_flags = TH_PUSH | TH_ACK; + p.tcph = &tcph; + p.flowflags = FLOW_PKT_TOSERVER; + p.payload = packet; + + p.tcph->th_seq = htonl(3184324453UL); + p.tcph->th_ack = htonl(3373419609UL); + p.payload_len = 2; + + if (StreamTcpReassembleHandleSegment(ra_ctx,&ssn, &stream, &p) == -1) { + printf("failed in segment reassmebling\n"); + result &= 0; + goto end; + } + + p.tcph->th_seq = htonl(3184324455UL); + p.tcph->th_ack = htonl(3373419621UL); + p.payload_len = 2; + + if (StreamTcpReassembleHandleSegment(ra_ctx,&ssn, &stream, &p) == -1) { + printf("failed in segment reassmebling\n"); + result &= 0; + goto end; + } + + p.tcph->th_seq = htonl(3184324453UL); + p.tcph->th_ack = htonl(3373419621UL); + p.payload_len = 6; + + if (StreamTcpReassembleHandleSegment(ra_ctx,&ssn, &stream, &p) == -1) { + printf("failed in segment reassmebling\n"); + result &= 0; + goto end; + } + + if(stream.seg_list_tail->payload_len != 4) { + printf("failed in segment reassmebling\n"); + result &= 0; + } + +end: + StreamTcpReturnStreamSegments(&stream); + StreamTcpFreeConfig(TRUE); + if (stream_memuse == 0) { + result &= 1; + } else { + printf("stream_memuse %"PRIu32"\n", stream_memuse); + } + return result; +} + +/** \test Test the stream mem leaks conditions. */ +static int StreamTcpTest24(void) +{ + TcpSession ssn; + Packet p; + Flow f; + TCPHdr tcph; + TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); + TcpStream stream; + memset(&stream, 0, sizeof (TcpStream)); + stream.os_policy = OS_POLICY_BSD; + uint8_t packet[1460] = ""; + int result = 1; + + StreamTcpInitConfig(TRUE); + + /* prevent L7 from kicking in */ + StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOSERVER, 4096); + StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOCLIENT, 4096); + StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); + StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); + + memset(&ssn, 0, sizeof (TcpSession)); + memset(&p, 0, sizeof (Packet)); + memset(&f, 0, sizeof (Flow)); + memset(&tcph, 0, sizeof (TCPHdr)); + f.protoctx = &ssn; + p.src.family = AF_INET; + p.dst.family = AF_INET; + p.proto = IPPROTO_TCP; + p.flow = &f; + tcph.th_win = 5480; + tcph.th_flags = TH_PUSH | TH_ACK; + p.tcph = &tcph; + p.flowflags = FLOW_PKT_TOSERVER; + p.payload = packet; + + p.tcph->th_seq = htonl(3184324455UL); + p.tcph->th_ack = htonl(3373419621UL); + p.payload_len = 4; + + if (StreamTcpReassembleHandleSegment(ra_ctx,&ssn, &stream, &p) == -1) { + printf("failed in segment reassmebling\n"); + result &= 0; + goto end; + } + + p.tcph->th_seq = htonl(3184324459UL); + p.tcph->th_ack = htonl(3373419633UL); + p.payload_len = 2; + + if (StreamTcpReassembleHandleSegment(ra_ctx,&ssn, &stream, &p) == -1) { + printf("failed in segment reassmebling\n"); + result &= 0; + goto end; + } + + p.tcph->th_seq = htonl(3184324459UL); + p.tcph->th_ack = htonl(3373419657UL); + p.payload_len = 4; + + if (StreamTcpReassembleHandleSegment(ra_ctx,&ssn, &stream, &p) == -1) { + printf("failed in segment reassmebling\n"); + result &= 0; + goto end; + } + + if(stream.seg_list_tail->payload_len != 2) { + printf("failed in segment reassmebling\n"); + result &= 0; + } + +end: + StreamTcpReturnStreamSegments(&stream); + StreamTcpFreeConfig(TRUE); + if (stream_memuse == 0) { + result &= 1; + } else { + printf("stream_memuse %"PRIu32"\n", stream_memuse); + } + return result; +} + #endif /* UNITTESTS */ void StreamTcpRegisterTests (void) { @@ -5177,6 +5344,8 @@ void StreamTcpRegisterTests (void) { UtRegisterTest("StreamTcpTest20 -- setup OS policy", StreamTcpTest20, 1); UtRegisterTest("StreamTcpTest21 -- setup OS policy", StreamTcpTest21, 1); UtRegisterTest("StreamTcpTest22 -- setup OS policy", StreamTcpTest22, 1); + UtRegisterTest("StreamTcpTest23 -- stream memory leaks", StreamTcpTest23, 1); + UtRegisterTest("StreamTcpTest24 -- stream memory leaks", StreamTcpTest24, 1); /* set up the reassembly tests as well */ StreamTcpReassembleRegisterTests(); #endif /* UNITTESTS */ diff --git a/src/util-classification-config.c b/src/util-classification-config.c index b25e03a972..3842ae3b00 100644 --- a/src/util-classification-config.c +++ b/src/util-classification-config.c @@ -227,11 +227,21 @@ static inline int SCClassConfAddClasstype(char *rawstr, DetectEngineCtx *de_ctx) SCLogDebug("HashTable Add failed"); } else { SCLogDebug("Duplicate classtype found inside classification.config"); + if (ct_new->classtype_desc) free(ct_new->classtype_desc); + if (ct_new->classtype) free (ct_new->classtype); + free(ct_new); } + if (ct_name) free((char *)ct_name); + if (ct_desc) free((char *)ct_desc); + if (ct_priority_str) free((char *)ct_priority_str); return 0; error: + if (ct_name) free((char *)ct_name); + if (ct_desc) free((char *)ct_desc); + if (ct_priority_str) free((char *)ct_priority_str); + return -1; }