tag: fixes and cleanups

Major fixes for the tag subsystem:

- Removed TimeGet call from tag packet runtime to safe a gettimeofday
- Removed unused lock from data type
- Fixed broken first packet skip logic
- Fix broken reference counter logic
- Fix memory leak on tag expiration
- Cleaned up code
remotes/origin/master-1.1.x
Victor Julien 14 years ago
parent b7b58074de
commit 3401defbbb

@ -35,8 +35,8 @@
static void TagTimeoutRemove(DetectTagHostCtx *tag_ctx, struct timeval *tv);
SC_ATOMIC_DECLARE(unsigned int, num_tags); /**< Atomic counter, to know if we
have tagged hosts/sessions,
to avoid locking */
have tagged hosts/sessions,
to avoid locking */
/* Global Ctx for tagging hosts */
DetectTagHostCtx *tag_ctx = NULL;
@ -136,10 +136,13 @@ void TagDestroyCtx(void)
tag_ctx->tag_hash_table_ipv6 = NULL;
SCMutexDestroy(&tag_ctx->lock);
SC_ATOMIC_DESTROY(num_tags);
SCFree(tag_ctx);
tag_ctx = NULL;
#ifdef DEBUG
BUG_ON(SC_ATOMIC_GET(num_tags) != 0);
#endif
SC_ATOMIC_DESTROY(num_tags);
}
/** \brief Reset the tagging engine context
@ -207,7 +210,7 @@ DetectTagDataEntryList *TagHashSearch(DetectTagHostCtx *tag_ctx, DetectTagDataEn
* \param p Packet structure
*
*/
void TagHashAdd(DetectTagHostCtx *tag_ctx, DetectTagDataEntryList *dtde, Packet *p)
int TagHashAdd(DetectTagHostCtx *tag_ctx, DetectTagDataEntryList *dtde, Packet *p)
{
SCEnter();
@ -223,7 +226,7 @@ void TagHashAdd(DetectTagHostCtx *tag_ctx, DetectTagDataEntryList *dtde, Packet
dtde, sizeof(DetectTagDataEntry));
}
SCReturn;
SCReturnInt((ret == 0));
}
/**
@ -237,20 +240,19 @@ void TagHashAdd(DetectTagHostCtx *tag_ctx, DetectTagDataEntryList *dtde, Packet
*/
int TagHashAddTag(DetectTagHostCtx *tag_ctx, DetectTagDataEntry *tde, Packet *p)
{
SCEnter();
DetectTagDataEntryList *entry = NULL;
uint8_t updated = 0;
uint16_t num_tags = 0;
/* local, just for searching */
DetectTagDataEntryList tdl;
tdl.header_entry = NULL;
tdl.header_entry = tde;
SCEnter();
SCMutexLock(&tag_ctx->lock);
/* first search if we already have an entry of this host */
DetectTagDataEntryList *entry = NULL;
if (PKT_IS_IPV4(p)) {
tdl.ipv = 4;
if (tde->td->direction == DETECT_TAG_DIR_SRC) {
@ -272,7 +274,23 @@ int TagHashAddTag(DetectTagHostCtx *tag_ctx, DetectTagDataEntry *tde, Packet *p)
DetectTagDataEntryList *new = SCMalloc(sizeof(DetectTagDataEntryList));
if (new != NULL) {
memcpy(new, &tdl, sizeof(DetectTagDataEntryList));
TagHashAdd(tag_ctx, new, p);
/* get a new tde as the one we have is on the stack */
DetectTagDataEntry *new_tde = DetectTagDataCopy(tde);
if (new_tde == NULL) {
SCFree(new);
} else {
new->header_entry = new_tde;
}
/* increment num_tags before adding to prevent a minor race,
* on setting and checking the first tag */
SC_ATOMIC_ADD(num_tags, 1);
if (!(TagHashAdd(tag_ctx, new, p))) {
SC_ATOMIC_SUB(num_tags, 1);
SCFree(new_tde);
SCFree(new);
}
} else {
SCLogDebug("Failed to allocate a new session");
}
@ -301,12 +319,16 @@ int TagHashAddTag(DetectTagHostCtx *tag_ctx, DetectTagDataEntry *tde, Packet *p)
/* If there was no entry of this rule, append the new tde */
if (updated == 0 && num_tags < DETECT_TAG_MAX_TAGS) {
tde->next = entry->header_entry;
entry->header_entry = tde;
/* get a new tde as the one we have is on the stack */
DetectTagDataEntry *new_tde = DetectTagDataCopy(tde);
if (new_tde != NULL) {
SC_ATOMIC_ADD(num_tags, 1);
new_tde->next = entry->header_entry;
entry->header_entry = new_tde;
}
} else if (num_tags == DETECT_TAG_MAX_TAGS) {
SCLogDebug("Max tags for sessions reached (%"PRIu16")", num_tags);
}
}
SCMutexUnlock(&tag_ctx->lock);
@ -321,8 +343,9 @@ int TagHashAddTag(DetectTagHostCtx *tag_ctx, DetectTagDataEntry *tde, Packet *p)
* \param p packet
*
*/
void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
Packet *p) {
void TagHandlePacket(DetectEngineCtx *de_ctx,
DetectEngineThreadCtx *det_ctx, Packet *p)
{
DetectTagDataEntry *tde = NULL;
DetectTagDataEntry *prev = NULL;
@ -331,14 +354,12 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
DetectTagDataEntryList *tde_src = NULL;
DetectTagDataEntryList *tde_dst = NULL;
unsigned int current_tags = SC_ATOMIC_GET(num_tags);
/* If there's no tag, get out of here */
unsigned int current_tags = SC_ATOMIC_GET(num_tags);
if (current_tags == 0)
return;
uint8_t flag_added = 0;
struct timeval ts = { 0, 0 };
TimeGet(&ts);
/* First update and get session tags */
if (p->flow != NULL) {
@ -348,13 +369,15 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
prev = NULL;
while (iter != NULL) {
/* update counters */
iter->last_ts.tv_sec = ts.tv_sec;
iter->last_ts.tv_sec = p->ts.tv_sec;
iter->packets++;
iter->bytes += GET_PKT_LEN(p);
/* If this packet triggered the rule with tag, we dont need
* to log it (the alert will log it) */
if (iter->first_time++ > 0) {
if (iter->skipped_first == 0) {
iter->skipped_first = 1;
} else if (iter->td != NULL) {
/* Update metrics; remove if tag expired; and set alerts */
switch (iter->td->metric) {
case DETECT_TAG_METRIC_PACKET:
@ -451,9 +474,9 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
SCMutexLock(&tag_ctx->lock);
/* Check for timeout tags if we reached the interval for checking it */
if (ts.tv_sec - tag_ctx->last_ts.tv_sec > TAG_TIMEOUT_CHECK_INTERVAL) {
TagTimeoutRemove(tag_ctx, &ts);
tag_ctx->last_ts.tv_sec = ts.tv_sec;
if (p->ts.tv_sec - tag_ctx->last_ts.tv_sec > TAG_TIMEOUT_CHECK_INTERVAL) {
TagTimeoutRemove(tag_ctx, &p->ts);
tag_ctx->last_ts.tv_sec = p->ts.tv_sec;
}
if (PKT_IS_IPV4(p)) {
@ -481,13 +504,15 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
prev = NULL;
while (iter != NULL) {
/* update counters */
iter->last_ts.tv_sec = ts.tv_sec;
iter->last_ts.tv_sec = p->ts.tv_sec;
iter->packets++;
iter->bytes += GET_PKT_LEN(p);
/* If this packet triggered the rule with tag, we dont need
* to log it (the alert will log it) */
if (iter->first_time++ > 0 && iter->td != NULL) {
if (iter->skipped_first == 0) {
iter->skipped_first = 1;
} else if (iter->td != NULL) {
/* Update metrics; remove if tag expired; and set alerts */
switch (iter->td->metric) {
case DETECT_TAG_METRIC_PACKET:
@ -497,14 +522,15 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
tde = iter;
prev->next = iter->next;
iter = iter->next;
DetectTagDataEntryFree(tde);
SCFree(tde);
SC_ATOMIC_SUB(num_tags, 1);
continue;
} else {
tde = iter;
iter = iter->next;
SCFree(tde);
SC_ATOMIC_SUB(num_tags, 1);
tde_src->header_entry = NULL;
tde_src->header_entry = iter;
continue;
}
} else if (flag_added == 0) {
@ -521,14 +547,15 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
tde = iter;
prev->next = iter->next;
iter = iter->next;
DetectTagDataEntryFree(tde);
SCFree(tde);
SC_ATOMIC_SUB(num_tags, 1);
continue;
} else {
tde = iter;
iter = iter->next;
SCFree(tde);
SC_ATOMIC_SUB(num_tags, 1);
tde_src->header_entry = NULL;
tde_src->header_entry = iter;
continue;
}
} else if (flag_added == 0) {
@ -547,14 +574,15 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
tde = iter;
prev->next = iter->next;
iter = iter->next;
DetectTagDataEntryFree(tde);
SCFree(tde);
SC_ATOMIC_SUB(num_tags, 1);
continue;
} else {
tde = iter;
iter = iter->next;
SCFree(tde);
SC_ATOMIC_SUB(num_tags, 1);
tde_src->header_entry = NULL;
tde_src->header_entry = iter;
continue;
}
} else if (flag_added == 0) {
@ -567,6 +595,7 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
}
}
prev = iter;
iter = iter->next;
}
@ -577,13 +606,15 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
prev = NULL;
while (iter != NULL) {
/* update counters */
iter->last_ts.tv_sec = ts.tv_sec;
iter->last_ts.tv_sec = p->ts.tv_sec;
iter->packets++;
iter->bytes += GET_PKT_LEN(p);
/* If this packet triggered the rule with tag, we dont need
* to log it (the alert will log it) */
if (iter->first_time++ > 0 && iter->td != NULL) {
if (iter->skipped_first == 0) {
iter->skipped_first = 1;
} else if (iter->td != NULL) {
/* Update metrics; remove if tag expired; and set alerts */
switch (iter->td->metric) {
case DETECT_TAG_METRIC_PACKET:
@ -593,14 +624,15 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
tde = iter;
prev->next = iter->next;
iter = iter->next;
DetectTagDataEntryFree(tde);
SCFree(tde);
SC_ATOMIC_SUB(num_tags, 1);
continue;
} else {
tde = iter;
iter = iter->next;
SCFree(tde);
SC_ATOMIC_SUB(num_tags, 1);
tde_dst->header_entry = NULL;
tde_dst->header_entry = iter;
continue;
}
} else if (flag_added == 0) {
@ -617,14 +649,15 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
tde = iter;
prev->next = iter->next;
iter = iter->next;
DetectTagDataEntryFree(tde);
SCFree(tde);
SC_ATOMIC_SUB(num_tags, 1);
continue;
} else {
tde = iter;
iter = iter->next;
SCFree(tde);
SC_ATOMIC_SUB(num_tags, 1);
tde_dst->header_entry = NULL;
tde_dst->header_entry = iter;
continue;
}
} else if (flag_added == 0) {
@ -643,14 +676,15 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
tde = iter;
prev->next = iter->next;
iter = iter->next;
DetectTagDataEntryFree(tde);
SCFree(tde);
SC_ATOMIC_SUB(num_tags, 1);
continue;
} else {
tde = iter;
iter = iter->next;
SCFree(tde);
SC_ATOMIC_SUB(num_tags, 1);
tde_dst->header_entry = NULL;
tde_dst->header_entry = iter;
continue;
}
} else if (flag_added == 0) {
@ -683,9 +717,9 @@ static void TagTimeoutRemove(DetectTagHostCtx *tag_ctx, struct timeval *tv)
HashListTableBucket *next = NULL;
HashListTableBucket *buck = NULL;
DetectTagDataEntry *tde= NULL;
DetectTagDataEntry *tde = NULL;
DetectTagDataEntry *tmp = NULL;
DetectTagDataEntry *prev= NULL;
DetectTagDataEntry *prev = NULL;
DetectTagDataEntryList *tdl = NULL;

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2010 Open Information Security Foundation
/* Copyright (C) 2007-2011 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@ -49,9 +49,7 @@
#include "util-debug.h"
#include "threads.h"
extern SCSpinlock num_tags_sc_lock__;
extern unsigned int num_tags_sc_atomic__;
SC_ATOMIC_EXTERN(unsigned int, num_tags);
extern DetectTagHostCtx *tag_ctx;
/* format: tag: <type>, <count>, <metric>, [direction]; */
@ -99,6 +97,24 @@ error:
return;
}
DetectTagDataEntry *DetectTagDataCopy(DetectTagDataEntry *dtd) {
DetectTagDataEntry *tde = SCMalloc(sizeof(DetectTagDataEntry));
if (tde == NULL) {
return NULL;
}
memset(tde, 0, sizeof(DetectTagDataEntry));
tde->sid = dtd->sid;
tde->gid = dtd->gid;
tde->td = dtd->td;
tde->first_ts.tv_sec = dtd->first_ts.tv_sec;
tde->first_ts.tv_usec = dtd->first_ts.tv_usec;
tde->last_ts.tv_sec = dtd->last_ts.tv_sec;
tde->last_ts.tv_usec = dtd->last_ts.tv_usec;
return tde;
}
/**
* \brief This function is used to add a tag to a session (type session)
* or update it if it's already installed. The number of times to
@ -130,36 +146,41 @@ int DetectTagFlowAdd(Packet *p, DetectTagDataEntry *tde) {
memset(p->flow->tag_list, 0, sizeof(DetectTagDataEntryList));
} else {
iter = p->flow->tag_list->header_entry;
}
/* First iterate installed entries searching a duplicated sid/gid */
for (; iter != NULL; iter = iter->next) {
num_tags++;
if (iter->sid == tde->sid && iter->gid == tde->gid) {
iter->cnt_match++;
/* If so, update data, unless the maximum MATCH limit is
* reached. This prevents possible DOS attacks */
if (iter->cnt_match < DETECT_TAG_MATCH_LIMIT) {
/* Reset time and counters */
iter->first_ts.tv_sec = iter->last_ts.tv_sec = tde->first_ts.tv_sec;
iter->packets = 0;
iter->bytes = 0;
/* First iterate installed entries searching a duplicated sid/gid */
for (; iter != NULL; iter = iter->next) {
num_tags++;
if (iter->sid == tde->sid && iter->gid == tde->gid) {
iter->cnt_match++;
/* If so, update data, unless the maximum MATCH limit is
* reached. This prevents possible DOS attacks */
if (iter->cnt_match < DETECT_TAG_MATCH_LIMIT) {
/* Reset time and counters */
iter->first_ts.tv_sec = iter->last_ts.tv_sec = tde->first_ts.tv_sec;
iter->packets = 0;
iter->bytes = 0;
}
updated = 1;
break;
}
updated = 1;
break;
}
}
/* If there was no entry of this rule, prepend the new tde */
if (updated == 0 && num_tags < DETECT_TAG_MAX_TAGS) {
tde->next = p->flow->tag_list->header_entry;
p->flow->tag_list->header_entry = tde;
DetectTagDataEntry *new_tde = DetectTagDataCopy(tde);
if (new_tde != NULL) {
new_tde->next = p->flow->tag_list->header_entry;
p->flow->tag_list->header_entry = new_tde;
SC_ATOMIC_ADD(num_tags, 1);
}
} else if (num_tags == DETECT_TAG_MAX_TAGS) {
SCLogDebug("Max tags for sessions reached (%"PRIu16")", num_tags);
}
SCMutexUnlock(&p->flow->m);
return updated;
error:
@ -181,50 +202,35 @@ error:
int DetectTagMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m)
{
DetectTagData *td = (DetectTagData *) m->ctx;
DetectTagDataEntry *tde = NULL;
tde = SCMalloc(sizeof(DetectTagDataEntry));
if (tde == NULL) {
return 1;
}
memset(tde, 0, sizeof(DetectTagDataEntry));
tde->sid = s->id;
tde->gid = s->gid;
tde->td = td;
TimeGet(&tde->first_ts);
tde->last_ts.tv_sec = tde->first_ts.tv_sec;
DetectTagDataEntry tde;
memset(&tde, 0, sizeof(DetectTagDataEntry));
tde.sid = s->id;
tde.gid = s->gid;
tde.td = td;
tde.last_ts.tv_sec = tde.first_ts.tv_sec = p->ts.tv_usec;
switch (td->type) {
case DETECT_TAG_TYPE_HOST:
if (td->direction == DETECT_TAG_DIR_SRC || td->direction == DETECT_TAG_DIR_DST) {
SCLogDebug("Tagging Host with sid %"PRIu32":%"PRIu32"", s->id, s->gid);
if (TagHashAddTag(tag_ctx, tde, p) == 1)
SCFree(tde);
else
SC_ATOMIC_ADD(num_tags, 1);
} else {
SCLogError(SC_ERR_INVALID_VALUE, "Error on direction of a tag keyword (not src nor dst)");
SCFree(tde);
}
#ifdef DEBUG
BUG_ON(!(td->direction == DETECT_TAG_DIR_SRC || td->direction == DETECT_TAG_DIR_DST));
#endif
SCLogDebug("Tagging Host with sid %"PRIu32":%"PRIu32"", s->id, s->gid);
TagHashAddTag(tag_ctx, &tde, p);
break;
case DETECT_TAG_TYPE_SESSION:
if (p->flow != NULL) {
/* If it already exists it will be updated */
if (DetectTagFlowAdd(p, tde) == 1)
SCFree(tde);
else
SC_ATOMIC_ADD(num_tags, 1);
DetectTagFlowAdd(p, &tde);
} else {
SCLogDebug("No flow to append the session tag");
SCFree(tde);
}
break;
#ifdef DEBUG
default:
SCLogError(SC_ERR_INVALID_VALUE, "Error on type of a tag keyword (not session nor host)");
SCFree(tde);
SCLogDebug("unknown type of a tag keyword (not session nor host)");
BUG_ON(1);
break;
#endif
}
return 1;
@ -392,8 +398,15 @@ error:
void DetectTagDataListFree(void *ptr) {
if (ptr != NULL) {
DetectTagDataEntryList *list = (DetectTagDataEntryList *)ptr;
DetectTagDataEntryFree(list->header_entry);
SCFree(ptr);
DetectTagDataEntry *entry = list->header_entry;
while (entry != NULL) {
DetectTagDataEntry *next_entry = entry->next;
DetectTagDataEntryFree(entry);
SC_ATOMIC_SUB(num_tags, 1);
entry = next_entry;
}
SCFree(list);
}
}
/**
@ -405,9 +418,6 @@ void DetectTagDataListFree(void *ptr) {
void DetectTagDataEntryFree(void *ptr) {
if (ptr != NULL) {
DetectTagDataEntry *dte = (DetectTagDataEntry *)ptr;
if (dte->next != NULL)
DetectTagDataEntryFree(dte->next);
dte->next = NULL;
SCFree(dte);
}
}

@ -64,9 +64,9 @@ enum {
/** This will be the rule options/parameters */
typedef struct DetectTagData_ {
uint8_t type; /**< tag type */
uint8_t direction; /**< host direction */
uint32_t count; /**< count */
uint32_t metric; /**< metric */
uint8_t direction; /**< host direction */
} DetectTagData;
/** This is the installed data at the session/global or host table */
@ -81,7 +81,7 @@ typedef struct DetectTagDataEntry_ {
struct DetectTagDataEntry_ *next; /**< Pointer to the next tag of this
* session/src_host/dst_host (if any from other rule) */
uint16_t cnt_match; /**< number of times this tag was reset/updated */
uint8_t first_time; /**< Used at unified output. The first packet write the
uint8_t skipped_first; /**< Used for output. The first packet write the
header with the data of the sig. The next packets use
gid/sid/rev of the tagging engine */
} DetectTagDataEntry;
@ -90,14 +90,14 @@ typedef struct DetectTagDataEntryList_ {
DetectTagDataEntry *header_entry;
Address addr; /**< Var used to store dst or src addr */
uint8_t ipv; /**< IP Version */
SCMutex lock;
}DetectTagDataEntryList;
} DetectTagDataEntryList;
/* prototypes */
void DetectTagRegister (void);
void DetectTagDataFree(void *ptr);
void DetectTagDataEntryFree(void *ptr);
void DetectTagDataListFree(void *ptr);
DetectTagDataEntry *DetectTagDataCopy(DetectTagDataEntry *dtd);
#endif /* __DETECT_TAG_H__ */

Loading…
Cancel
Save