pthread_getattr_np re-initializes the attributes on use causing the
original pthread_attr_init to leak. Destroy after use to prevent the
memory leak.
Ticket: 9032
(cherry picked from commit 7a3d21bb2c)
This patch distinguishes malformed DHCP options from truncated ones.
Previously, the malformed_options field was never set and parsing errors in
overloaded file and sname fields were silently discarded.
This caused malformed options to be reported as truncated or not reported at all.
Classify errors in the primary option stream and overloaded fields.
Treat failures within fixed-size overloaded fields as malformed because those
fields are already fully present.
Ticket #8874
(cherry picked from commit e89b7644a8)
DHCP lease, renewal, and rebinding time options contain a four-byte value,
but the parser previously ignored their declared length and always consumed
four bytes.
Reject these options unless their length is exactly four to
prevent parser desynchronization and incorrect keyword matches.
Ticket #8873
(cherry picked from commit 382b18da9b)
DHCP option 0 is a one-byte padding field, but it was parsed as a generic TLV.
This consumed the following option code as its length and could prevent later
options from being inspected.
Handle PAD explicitly so parsing resumes at the next option.
Ticket #8819
(cherry picked from commit a06e7c7422)
Since the PostgreSQL protocol doesn't impose any clear limits to how
many responses a backend could send, add one to the app-proto parser.
Using 21-64 as the accepted values, and 64 as the default:
The Start-up phase may have up to 17-18 ParameterStatus messages, plus
AuthOk, BackendKeyData and ReadyForQuery: 20, with extra room to be on
the safer side: 21
And 64 as upper limit, because as we currently summarize query
responses, we already don't get flooded by DataRow and Copy responses
messages, so we don't expect to see that many responses in a single
transaction for the pgsql, with the current implementation.
Ticket: #7263
(cherry picked from commit f839581dba)
Pgsql logger would only open a ParameterStatus message array and only
close it when a different type of message was seen (following an
expected pgsql transaction style). However, if no different type of
message followed the ParameterStatus message, the array remained open,
leading to an unbalanced `}` count, and poisoning the whole JSON log,
from that point on.
Now, if we finish the responses logging loop without reaching another
type of response, close the array, regardless.
Ticket: #9012
(cherry picked from commit 85168b8036)
Add the pgsql.response fields: row_description_malformed and
field_count to the list, as they're relevant to the patch at hand.
Part of
Ticket: #8885
(cherry picked from commit a27c663de8)
parse_row_description and parse_consolidated_data_row read a field_count
from the message body and use that to iterate a slice, without checking
whether the count actually fits the body.
A backend-controlled attack could lead to fewer fields logged, or
stalling of the parser to-client direction for the duration of the flow.
A malformed_response event is set for pgsql, if either of those
message's inner parsers has a field_count that can't be reconciled with
the body slice.
A new pgsql.response log field is added to indicate this, too:
pgsql.response.row_description_malformed, a boolean. This wasn't added
to the consolidated data row message, per its summarization nature.
The row_description unit test buffer declared a length one byte longer
than its three fields occupy. The old code silently discarded that
surplus byte; the new one reports it, so the buffer was corrected.
Ticket: #8885
(cherry picked from commit fe939e8da7)
Create a TX to carry the event if needed. Requires passing if the event is
created on the request or response, for the tx allocation.
Ticket: 8979
(cherry picked from commit d53344f103)
Treat bad link-header CRCs and impossible link lengths as recoverable
errors and attempt to resynchronize.
Also consume a response frame whose trusted length is too short for the
required response headers, so later responses remain available.
Ticket: 8980
(cherry picked from commit 92df7e4a8e)
Ticket: 8916
Avoid type confusion and possible overread when calling
AppLayerParserGetStateProgress
DetectEngineInspectMultiBufferGeneric callback may be called with
the inner DNS tx of a HTTP2/DOH2 tx, so we should use dns as its
protocol
(cherry picked from commit 5284906338)
Avoids pushing multiple log messages, when the consumer will
only set one app-layer event for the tx
Ticket: 8867
(cherry picked from commit 72829dbaea)
Avoids pushing multiple log messages, when the consumer will
only set one app-layer event for the tx
Also, this is a warning, not an error, as we continue parsing.
Ticket: 8867
(cherry picked from commit 4dd7ebf079)
Ticket: 8800
Thus avoiding unbounded recursion
Before that, parse_payload could call
parse_security_association_payload which could call back
parse_payload if a type in the list was SecurityAssociation
But a Security Association only accepts the type Proposal in its
payload, see RFC 2408: section 3.5
There was another recursive path with parse_payload calling
parse_proposal_payload which called back parse_payload
And a Proposal only accepts the type Transform in its payload, see
RFC 2408: section 3.6
(cherry picked from commit b13c742a9c)
Fixes: 9aeeac53 ("pgsql: remove probe_ts function")
When the probe_ts function was removed in 9aeeac532, the request gap
handling got inverted, preventing re-sync of the app-proto from the
frontend side.
This could lead to detection evasion after a gap.
Ticket: #8822
(cherry picked from commit 7f4d44edc1)
Ticket: 8755
The config parameter was only taken into account from the
settings frame HEADER_TABLE_SIZE
Emits an event http2.header_table_overflow when we have the first
header that we cannot keep in Suricata's memory due to the
configured limit.
(cherry picked from commit 521deb07d6)
We need to find or create tx first.
So that if there is something weird with the first tx,
we set the event to it instead of discarding it
(cherry picked from commit ec869b18c7)
DetectBytetestValidateNbytesOnly() only performed signed upper-bound
checks but had no lower-bound guard.
Ticket: #8821.
(cherry picked from commit ea4fc20b9a)
DetectBytejumpValidateNbytesOnly() only performed signed upper-bound
checks but had no lower-bound guard. When byte_jump used a
variable-supplied nbytes value derived from byte_extract/byte_math, an
extracted field with bit 31 set arrived as a negative int32_t that
passed validation and the ptr+len boundary check.
The downstream (uint16_t)nbytes truncation in the binary extract branch
then produced a small positive count and ByteExtractUint64() over-read
up to 7 bytes past the end of the inspection buffer.
Address this by adding a nbytes >= 0 check.
Ticket: #8831.
(cherry picked from commit bfce4d1f7d)
Fix an infinite loop in SCInspectionBufferCheckAndExpand where doubling
a uint32_t new_size can overflow if min_size is too large. This causes
detection worker threads to spin at 100% CPU. This is a very unlikely
scenario, but this patch hardens the logic to be defensive.
Ticket: #8834.
(cherry picked from commit 40942ed64c)
DetectFileInspect() walks the per-signature SigMatchData array with
a pointer (smd) that is incremented inside the inner keyword-matching
loop. Because smd is the function parameter, this mutation persists
across iterations of the outer for file loop and there is no reset
of the cursor between files.
With a single file this works correctly. In any transaction that carries
two or more File objects every subsequent file is evaluated starting at
the already-advanced smd instead of the beginning of the keyword chain,
leading to skipping of keywords.
This patch addresses the issue by using a local iterator instead of
using the function parameter directly, so every file sees the full keyword
list.
Ticket: #8815.
(cherry picked from commit 67e8779659)
PrefilterPostRuleMatch() repopulates det_ctx->pmq with flowbits:isset
candidates after a matching flowbits:set rule is found. The subsequent
append loop writes directly into det_ctx->tx_candidates[] without first
checking that the array has room.
The buffer was initially sized for prefilter results only not accounting
for post-rule additions. When array_idx already equals tx_candidates_size,
the writes go past the end of the heap-allocated block - a heap buffer
overflow followed by qsort() over OOB memory, causing a crash (DoS).
Addressed by adding a capacity check + expand before the append loop,
matching the existing pattern at all other candidate append logic.
Ticket: #8866.
(cherry picked from commit fa76410603)
Ticket: 8973
Before that, the update to DoH2 happened before http1 state was
freed, leading to a type confusion.
In case of a HTTP1->HTTP2 upgrade, if the client sends a DOH2
request, Suricata went to change again the flow's alproto
with SCAppLayerForceProtocolChange
But SCAppLayerForceProtocolChange did not take into account the
fact that we were doing a HTTP1->HTTP2 upgrade, and the previous
HTTP1 state was not freed yet.
Now SCAppLayerForceProtocolChange checks FlowChangeProto
and update alproto_orig only if we were not doing a proto change
already, as alproto_orig is used to know which type of state
to free.
(cherry picked from commit c9ca1a4fba)
parse_t123_tpkt runs the X.224 and X.223/MCS sub-parsers over the
length-bounded tpkt payload, but they use streaming nom parsers.
An inner length field overrunning the payload, such as an oversized
CS_CORE block, escaped as Err::Incomplete although the tpkt was fully
present.
This patch wraps the child parsers in complete() so Incomplete from within the
bounded payload becomes an Error.
The tpkt is then returned as an unrecognized Raw child, which the caller skips,
and parsing resumes at the next tpkt.
Ticket #8838
(cherry picked from commit 8c9bca92fb)
When an incomplete SSH_MSG_KEXINIT record has a body of at least
SSH_MAX_REASSEMBLED_RECORD_LEN bytes and hassh is enabled, record_left
was overwritten with the full body length even though the function
returns ok() and thus consumes the body bytes already present in the
input. The next call then over-skipped by that many bytes into the
following record, desynchronising the parser for that direction so
hassh was never computed and ssh.hassh keywords could not match.
This patch keeps the record_left computed from the bytes actually consumed in
the oversized path, and only use the full body length in the path that
returns incomplete, where the body bytes are delivered again.
Ticket #8837
(cherry picked from commit f13021e022)
Also, reject a hash with no context so a Lua error is raised rather than
passing NULL to the hashing function.
Ticket: 9001
(cherry picked from commit 76189e4526)
MQTT5 logs user properties wherein a user can send any metadata
over the wire in the form of key-value pairs.
MQTT logger used these key-value pairs directly to populate the common
"properties" field. But we do not want to use arbitrary json keys
(which may contain arbitrary characters)
1. A fixed new child object to the common "properties" called
"user_properties" which carries a list of dicts.
2. Each key-value pair received as a part of the user properties is now
saved as:
"properties": {
...
"user_properties": [{"key": "mykey", "value": "myvalue"}]
...
}
instead of:
"properties": {
...
"key": "value"
...
}
Ticket: 8785
(cherry picked from commit 9dfc132e33)
Keys were not encoded as json UTF-8 strings.
This allowed json injection/corruption when an attacker
could control the key and put special JSON chars in it
such as double quote. Encode the keys when needed.
Ticket: 8999
(cherry picked from commit 07e83bff3d)
Ticket: 9003
When a single tx is getting inspected by rules having
http.response_header keyword both with a transform and without
a transform, the code went like this :
Http2ThreadMultiBuf structure contains a list (Vec) of buffers
(Vec<u8>) and owns these Vec<u8> (they are not owned by the tx).
For the first list_id, we computed each buffer for a http2 header
and put them in these Http2ThreadMultiBuf structure.
But for the second list_id, the code began by freeing the memory
of these http2 headers, and reallocated new buffers (Vec<u8>)
and recomputed each buffer.
After these rounds, which may happen in DetectRunPrefilterTx,
the buffers might need further checks, hence the use-after-free.
Now, the code does not free and allocate a new buffer, it just rewrites
the old one, as is done for HTTP1.
(cherry picked from commit 96c6ba6f76)
While in gap state, if a parse attempt failed, the protocol return error
preventing future retries to get out of gap state.
Ticket: 8949
(cherry picked from commit 03dac6d7fb)
Due to a lack of tests with varied ErrorResponse messages, it wasn't
noticed before that these were missing.
Partially covers
Ticket: #8903
Related to
Bug: #8886
(cherry picked from commit 41ebbdf499)
CopyIn and CopyOut message parsers read the length field, but did not
use that information to parse the rest of the message, instead, parsing
as many columns as indicated in the columns field, without ever
checking against the informed length. This opened the door for
attackers to fabricate messages that were never sent by the server,
as well as to obfuscate following valid backend messages, in case the
columns value was bigger than the actual message (up to ~128KiB).
Those parsers also had a message length parsing check off-by-one, fixed
in this patch.
When a malformed CopyIn or CopyOut response is seen, it is logged as
previously, with a new field added to indicate whether it is malformed
or not.
Ticket: #8863
(cherry picked from commit 8b5fb9b044)
parse_request and parse_response were using the parser state for
transaction bookkeeping.
Instead, use the message types themselves.
This change means that message types that ended up not being added to
the responses array, before (due to not advancing the parser state), now
are pushed and thus can be logged.
** Noticeable effect: AuthenticationSSPI, Notice and Notification
messages, previously missed due to falling into the None state progress
branch, could now get logged.
** To prevent affecting existing setups that don't expect these, since
they weren't logged before, we refrain from pushing them into the
responses queue, for now.
Leave state progress for state machine keeping.
Bug: #8886
(cherry picked from commit 42098ede68)
Ticket: 8775
Avoids that every flow that is the same except for spi
ends up in the same bucket, and that this bucket grow too much
since FlowCompareESP makes them different flows
(cherry picked from commit fabcc1f99d)
So far, the properties parsed across various different types of MQTT
messages was unbounded and could be exploited. Add a limit of 255 on the
maximum number of properties that any message type can store.
Additionally, raise an event for too many properties indicating an
anomaly in the network traffic.
Ticket: 8839
(cherry picked from commit df0e9f106b)
UNKNOWN property carries 1 byte in the MQTTProperty enum variant. It is
neither logged nor matched on, so, don't store it.
Ticket: 8839
(cherry picked from commit ad9a9204e9)
In case there are way too many SANs parsed in a TLS packet, flag it as
an anomaly instead of just dealing with it.
Ticket: 8864
(cherry picked from commit e8cf1d95cb)