Victor Julien [Thu, 22 Jan 2015 18:24:35 +0000 (19:24 +0100)]
file: optimize file pruning
FilePrune would clear the files, but not free them and remove them
from the list. This lead to ever growing lists in some cases.
Especially in HTTP sessions with many transactions, this could slow
us down.
Victor Julien [Sat, 24 Jan 2015 13:10:11 +0000 (14:10 +0100)]
flow: lockless flow manager checks
Until this point, the flow manager would check for timed out flows
by walking the flow hash, locking first the hash row and then each
individual flow to get it's state and timestamp. To not be too
intrusive trylocks were used so that a busy flow wouldn't cause the
flow manager to wait for a long time while holding the hash row lock.
Building on the changes in handling of the flow state and lastts
fields, this patch changes the flow managers behavior.
It can now get a flows state atomically and the lastts can be safely
read while holding just the flow hash row lock. This allows the flow
manager to do the basic time out check much more cheaply:
1. it doesn't have to wait for getting a lock
2. it doesn't interupt the packet path
As a consequence the trylock is now also gone. A flow that returns
'true' on timeout is pretty much certainly not going to be busy so
we can safely lock it unconditionally. This also means the flow
manager now walks the entire row unconditionally and is guaranteed
to inspect each flow in the row.
To make sure the functions called before the flow lock don't
accidentally change the flow (which would require a lock) the args
to these flows are changed to const pointers.
Victor Julien [Sat, 24 Jan 2015 12:46:25 +0000 (13:46 +0100)]
flow: modify lastts update logic
In the lastts timeval struct field in the flow the timestamp of the
last packet to update is recorded. This allows for tracking the timeout
of the flow. So far, this value was updated under the flow lock and also
read under the flow lock.
This patch moves the updating of this field to the FlowGetFlowFromHash
function, where it updated at the point where both the Flow and the
Flow Hash Row lock are held. This guarantees that the field is only
updated when both locks are held.
This makes reading the field safe when either lock is held, which is the
purpose of this patch.
The flow manager, while holding the flow hash row lock, can now safely
read the lastts value. This allows it to do the flow timeout check
without actually locking the flow.
Victor Julien [Sat, 24 Jan 2015 12:18:51 +0000 (13:18 +0100)]
flow: change flow state logic
A flow has 3 states: NEW, ESTABLISHED and CLOSED.
For all protocols except TCP, a flow is in state NEW as long as just one
side of the conversation has been seen. When both sides have been
observed the state is moved to ESTABLISHED.
TCP has a different logic, controlled by the stream engine. Here the TCP
state is leading.
Until now, when parts of the engine needed to know the flow state, it
would invoke a per protocol callback 'GetProtoState'. For TCP this would
return the state based on the TcpSession.
This patch changes this logic. It introduces an atomic variable in the
flow 'flow_state'. It defaults to NEW and is set to ESTABLISHED for non-
TCP protocols when we've seen both sides of the conversation.
For TCP, the state is updated from the TCP engine directly.
The goal is to allow for access to the state without holding the Flow's
main mutex lock. This will later allow the Flow Manager(s) to evaluate
the Flow w/o interupting it.
Victor Julien [Thu, 22 Jan 2015 12:43:31 +0000 (13:43 +0100)]
tcp: add stream.reassembly.zero-copy-size option
The option sets in bytes the value at which segment data is passed to
the app layer API directly. Data sizes equal to and higher than the
value set are passed on directly.
Victor Julien [Fri, 16 Jan 2015 10:53:29 +0000 (11:53 +0100)]
tcp: zero copy fast path in app-layer reassembly
Create 2 'fast paths' for app layer reassembly. Both are about reducing
copying. In the cases described below, we pass the segment's data
directly to the app layer API, instead of first copying it into a buffer
than we then pass. This safes a copy.
The first is for the case when we have just one single segment that was
just ack'd. As we know that we won't use any other segment this round,
we can just use the segment data.
The second case is more aggressive. When the segment meets a certain
size limit (currently hardcoded at 128 bytes), we pass it to the
app-layer API directly. Thus invoking the app-layer somewhat more often
to safe some copies.
Ken Steele [Mon, 3 Nov 2014 03:27:07 +0000 (22:27 -0500)]
Further optimize merging mpm and non-mpm rule ID lists.
When reaching the end of either list, merging is no longer required,
simply walk down the other list.
If the non-MPM list can't have duplicates, it would be worth removing
the duplicate check for the non-MPM list when it is the only non-empty list
remaining.
Ken Steele [Tue, 14 Oct 2014 21:24:14 +0000 (17:24 -0400)]
Create optimized sig_arrays from sig_lists
Create a copy of the SigMatch data in the sig_lists linked-lists and store
it in an array for faster access and not next and previous pointers. The
array is then used when calling the Match() functions.
Ken Steele [Tue, 14 Oct 2014 20:08:59 +0000 (16:08 -0400)]
Change Match() function to take const SigMatchCtx*
The Match functions don't need a pointer to the SigMatch object, just the
context pointer contained inside, so pass the Context to the Match function
rather than the SigMatch object. This allows for further optimization.
Change SigMatch->ctx to have type SigMatchCtx* rather than void* for better
type checking. This requires adding type casts when using or assigning it.
The SigMatch contex should not be changed by the Match() funciton, so pass it
as a const SigMatchCtx*.
Ken Steele [Mon, 6 Oct 2014 14:00:36 +0000 (10:00 -0400)]
Prefetch the next signature pointer
Read one signature pointer ahead to prefetch the value.
Use a variable, sflags, for s->flags, since it is used many times and the
compiles doesn't know that the signatures structure doesn't change, so it
will reload s->flags.
Ken Steele [Fri, 3 Oct 2014 21:12:06 +0000 (17:12 -0400)]
In AC-Tile, convert from using pids for indexing to pattern index
Use an MPM specific pattern index, which is simply an index starting
at zero and incremented for each pattern added to the MPM, rather than
the externally provided Pattern ID (pid), since that can be much
larger than the number of patterns. The Pattern ID is shared across at
MPMs. For example, an MPM with one pattern with pid=8000 would result
in a max_pid of 8000, so the pid_pat_list would have 8000 entries.
The pid_pat_list[] is replaced by a array of pattern indexes. The PID is
moved to the SCACTilePatternList as a single value. The PatternList is
also indexed by the Pattern Index.
max_pat_id is no longer needed and mpm_ctx->pattern_cnt is used instead.
The local bitarray is then also indexed by pattern index instead of PID, making
it much smaller. The local bit array sets a bit for each pattern found
for this MPM. It is only kept during one MPM search (stack allocated).
One note, the local bit array is checked first and if the pattern has already
been found, it will stop checking, but count a match. This could result in
over counting matches of case-sensitve matches, since following case-insensitive
matches will also be counted. For example, finding "Foo" in "foo Foo foo" would
report finding "Foo" 2 times, mis-counting the third word as "Foo".
Ken Steele [Thu, 6 Nov 2014 19:57:53 +0000 (14:57 -0500)]
Fix bug in MPM rule array handling
In PmqMerge() use MpmAddSids() instead of blindly copying the src
rule list onto the end of the dst rule list, since there might not
be enough room in the dst list. MpmAddSids() will resize the dst array
if needed.
Also add code to MpmAddSids() MpmAddPid() to better handle the case
that realloc fails to get more space. It first tries 2x the needed
space, but if that fails, it tries for just 1x. If that fails resize
returns 0. For MpmAddPid(), if resize fails, the new pid is lost. For
MpmAddSids(), as many SIDs as will fit are added, but some will be
lost.
Ken Steele [Fri, 3 Oct 2014 17:30:57 +0000 (13:30 -0400)]
Dynamically resize pmq->rule_id_array
Rather than statically allocate 64K entries in every rule_id_array,
increase the size only when needed. Created a new function MpmAddSids()
to check the size before adding the new sids. If the array is not large
enough, it calls MpmAddSidsResize() that calls realloc and does error
checking. If the realloc fails, it prints an error and drops the new sids
on the floor, which seems better than exiting Suricata.
The size is increased to (current_size + new_count) * 2. This handles the
case where new_count > current_size, which would not be handled by simply
using current_size * 2. It should also be faster than simply reallocing to
current_size + new_count, which would then require another realloc for each
new addition.
Victor Julien [Tue, 19 Aug 2014 13:09:59 +0000 (15:09 +0200)]
AC: use local bit array
Use a local pattern bit array to making sure we don't match more than
once, in addition to the pmq bitarray that is still used for results
validation higher up in the rule matching process.
Why: pmq->pattern_id_bitarray is currently sometimes used in a
'stateful' way, meaning that for a single packet we run multiple
MPM's on the same pmq w/o resetting it.
The new bitarray is used to determine wherther we need to append the
patterns associated 'sids' list to the pmq rule_id_array.
It has been observed that MPM1 matches for PAT1, and MPM2 matches for
PAT1 as well. However, in MPM1 PAT1 doesn't have the same sids list.
In this case MPM2 would not add it's sids to the list, leading to missed
detection.
Victor Julien [Mon, 18 Aug 2014 14:05:16 +0000 (16:05 +0200)]
detect: Add negated MPM to non-MPM array
Treat negated MPM sigs as if non-MPM, so we consider them always.
As MPM results and non-MPM rules lists are now merged and considered
for further inspection, rules that need to be considerd when a pattern
is absent are caught in the middle.
As a HACK/workaround this patch adds them to the non-MPM list. This
causes them to be inspected each time.
Victor Julien [Mon, 18 Aug 2014 11:51:40 +0000 (13:51 +0200)]
Detect: create per sgh non-MPM rule array
Array of rule id's that are not using MPM prefiltering. These will be
merged with the MPM results array. Together these should lead to a
list of all the rules that can possibly match.
Victor Julien [Mon, 18 Aug 2014 11:19:07 +0000 (13:19 +0200)]
MPM: build sid list from MPM matches
Pmq add rule list: Array of uint32_t's to store (internal) sids from the MPM.
AC: store sids in the pattern list, append to Pmq::rule_id_array on match.
Detect: sort rule_id_array after it was set up by the MPM. Rule id's
(Signature::num) are ordered, and the rule's with the lowest id are to
be inspected first. As the MPM doesn't fill the array in order, but instead
'randomly' we need this sort step to assure proper inspection order.
Ken Steele [Fri, 5 Sep 2014 21:14:34 +0000 (17:14 -0400)]
Create a wrapper around DetectFlowvarProcessList() to check for empty list
Creates an inline wrapper to check for flowvarlist == NULL before calling
DetectFlowvarProcessList() to remove the overhead of checking since the
list is usually empty.
Victor Julien [Wed, 14 Jan 2015 22:49:54 +0000 (23:49 +0100)]
Fix OS X 10.10 unittest failure
Work around OS X 10.10 Yosemite returning EDEADLK on a rwlock wrlocked
then tested by wrtrylock. All other OS' (and versions of OS X that I
tested) seem to return EBUSY instead.
Travis Green [Tue, 23 Dec 2014 22:10:21 +0000 (15:10 -0700)]
Update reference.config
Updated reference.config to match ET Open reference.config found here:
https://rules.emergingthreats.net/open/suricata/reference.config
Due to startup error shown here:
root@xxxxxxx01:/etc/suricata/rules# /usr/bin/suricata -c /etc/suricata/suricata.yaml --pidfile /var/run/suricata.pid --af-packet
23/12/2014 -- 22:07:56 - <Error> - [ERRCODE: SC_ERR_REFERENCE_UNKNOWN(150)] - unknown reference key "osvdb". Supported keys are defined in reference.config file. Please have a look at the conf param "reference-config-file"
<...>
Killed
Eric Leblond [Mon, 15 Dec 2014 23:14:59 +0000 (00:14 +0100)]
output-json: fix duplicate logging
This patches is fixing a issue in the OutputJSONBuffer function. It
was writing to file the content of the buffer starting from the start
to the final offset. But as the writing is done for each JSON string
we are duplicating the previous events if we are reusing the same
buffer.
Duplication was for example triggered when we have multiple alerts
attached to a packet. In the case of two alerts, the first one was
logged twice more as the second one.