Commit Graph

19739 Commits (bf0df4f480cbde6ac708526f87f7e899f4033c0f)
 

Author SHA1 Message Date
Jason Ish 39828e1587 github-ci: factor FreeBSD build into reusable script 1 month ago
Jason Ish 4dfd62d5d8 rust: use cargo test --workspace
--all has been deprecated.
1 month ago
Jason Ish fc70f8e788 github-ci: factor out scan-build to a script
So the main part of the build can be used by other CI.
1 month ago
Jason Ish 2147b8f51c github-ci: add build with asan instrumented rust
Factor out most of the testing to a script in hopes that it can be
re-used by other CI systems.
1 month ago
Jason Ish 516636f26d github-ci: remove jq from mingw builds
It has been dropped from that platform.
1 month ago
Juliana Fajardini b778e8c06d clang-format: fix commit-filter off-by-one
The filter range excluded $first_commit itself, so the first commit on
the branch was never rewritten and single-commit branches failed.

Ticket: #9097
1 month ago
Juliana Fajardini 4f47e43a33 clang-format: more accurate script reports
Success was decided by matching git-clang-format's stdout against two
known strings. When it fails, e.g. on an invalid revision, it writes to
stderr only and leaves stdout empty, so the check reported a formatting
violation where there is an error.

The reformatting commands had the opposite problem. git-clang-format
exits 1 when it did reformat files, which they treated as a failure, so
branch, commit, cached and rewrite-branch all reported an error whenever
they had work to do.

Keep stderr in its own file and compare against the exit code instead.
Exit code 1 means formatting changes were found or made, 2 and up are
errors.

Ticket: #9097
1 month ago
Juliana Fajardini 6aa97aa8a9 clang-format: handle branch without commits
When a branch has no commits of its own, e.g. when it is the baseline
branch itself, git rev-list returns nothing and first_commit is empty.
The empty value was still used to build "$first_commit^", which git
rejects as a bad revision.

git-clang-format then failed without writing anything to stdout, which
the output check reads as "formatting required". Pushing the baseline
branch therefore failed the CI formatting check, reporting a style
violation that does not exist.

Report that there is nothing to format instead.
git rev-list also returns nothing when the baseline ref does not exist
as it only reports that on stderr, so verify the baseline separately to
keep that case a loud failure rather than a silent pass.

Ticket: #9097
1 month ago
Juliana Fajardini 1283580858 github-ci: skip format check on stable branches
Ticket: #9097
1 month ago
Philippe Antoine 8873259fc9 http2: decompress zstd encoding
Ticket: 7904
1 month ago
Philippe Antoine 103abc2d33 http1: decompress zstd encoding
Ticket: 7904

As for brotli, do not allow zstd as a stacked encoding
1 month ago
Philippe Antoine c3e9d421aa rust: add zstd dependency
Ticket: 7904
1 month ago
Philippe Antoine 02f79c0451 ci: exclude rust crates from scan-build 1 month ago
Samaresh Kumar Singh e6a45d6e4e defrag: make frag_end and tracker id conversions explicit
-fsanitize=implicit-conversion flags the frag_offset + data_len
narrowing into the uint16_t frag_end. For both IPv4 and IPv6, compute
frag_end after the too-large check so the sum always fits, and make the
narrowing an explicit cast.

For IPv6 this moves the existing IPV6_MAXPACKET check above the
frag_end assignment. It used to sit at the end of the branch, after
frag_end was already computed. Nothing reads frag_end in between, so
behaviour is the same. Oversize fragments are still dropped with
IPV6_FRAG_PKT_TOO_LARGE, and the wrap can no longer happen, which
matches the IPv4 path.

Also drop the vestigial int32 casts when assigning the uint32_t
tracker id.

Ticket: 8232
1 month ago
Samaresh Kumar Singh 38c9b1e0e0 defrag: avoid unsigned underflow in RB_NFIND search key
The seek into the fragment tree uses frag_offset - 1 as the RB_NFIND
key. frag_offset is uint16_t, so the subtraction promotes to int, and
for the first fragment of a datagram (offset 0) the -1 narrows back to
65535 when it is stored in the key. -fsanitize=implicit-conversion
flags this.

The - 1 has to stay. DefragRbFragCompare never returns 0, so RB_NFIND
is strictly greater rather than inclusive. With key = frag_offset it
returns the fragment after an existing node at the same offset and
leaves prev on that node, so the preceding fragment, which may overlap
from the left, is skipped. With key = frag_offset - 1 the same-offset
node is included and prev ends up on the real predecessor.

So guard only the offset 0 case:

    .offset = frag_offset ? frag_offset - 1 : 0,

For frag_offset == 0 the seek starts at RB_MIN either way, so this
keeps the current behaviour and drops the wrap to 65535.

Add two unit tests. DefragOutOfOrderFirstFragmentTest covers offset 0
arriving into a populated tree. DefragSameOffsetPrecedingOverlapTest
pins down the same-offset plus left-overlap case that tells
frag_offset - 1 and frag_offset apart.

Ticket: 8232
1 month ago
Philippe Antoine 79fd1826ef ftp: exclude imap from probing parser
Ticket: 8265
1 month ago
Philippe Antoine e9bf04e9e7 imap: probing parser to distinguish from ftp
Tickete: 8265

The traffic "USER CAPABILITY" could be interpreted as both ftp
or imap.
Add a probing parser to imap after detection of the " CAPABILITY"
pattern to try do disambiguate.
1 month ago
Juliana Fajardini 9b7938aec3 pgsql: truly disable by default
While the pgsql parser is disabled if its setting is present in the yaml
config file, it is actually enabled if truly defaulted, that is, if not
present in the settings.

Actually disable pgsql parsing and logging if not present in the
suricata.yaml config. This implies that eve output enabling isn't enough
to enable the parser, now.

Bug: #8349
1 month ago
Giuseppe Longo 814295e76c nfs: fix clippy errors 1 month ago
William Bland fe8b2f3d2a detect/analyzer: fix swapped output file pointers
EngineAnalysisFP(), CleanupFPAnalyzer(), and CleanupRuleAnalyzer() were writing
to and closing the wrong FILE* pointers. Fast pattern output was written to
rules_analysis.txt instead of rules_fast_pattern.txt, leaving the latter
effectively empty.

Restore the behavior from before c8615bcd4, which inadvertently swapped the
pointers.

Bug: #9007
1 month ago
Victor Julien d996d85dcf cppcheck: drop unreachable DEBUG_VALIDATE_BUG_ONs
Remove unreachable DEBUG_VALIDATE_BUG_ON statements.
1 month ago
Victor Julien a4e4c3cd7b smb: cap the OOO gap backstop by chunk count and inspect all open files
The byte backstop leaves many tiny OOO chunks unbounded, and the scan
only inspected the in-progress file, which an interleaved second
handle could hide. Add a chunk-count backstop (configured count, 1024
hard cap when disabled) and check every open file tx.

Ticket: #8791.
1 month ago
Victor Julien 3c9883b37c smb: rework the OOO file-data gap backstop to the queue limits
Replace the hardcoded 2 MiB gap backstop, which silently truncated
OOO file data, with the configured queue size per direction (1 GiB
hard cap when disabled), raising SMBEvent::TruncatedFileData. It runs
ahead of the chunk_left == 0 early return, and a gap reaching the
tracker tags the session gapped even when fully consumed.

Ticket: #8791.
1 month ago
Victor Julien b39984c87e smb: enforce the write/read queue limits
The SMB1 WRITE_ANDX/READ_ANDX handlers fed the file tracker
unconditionally and SMB2 only checked raw in-flight occupancy. Apply
the max-{read,write}-queue-{size,cnt} checks, projected onto actual
queue growth, to both protocols' found and create-new tx branches;
on overflow raise the queue event and skip the record's remainder.

Ticket: #8791.
1 month ago
Victor Julien 96d943d1c1 nfs: bound the chunk-continuation stream skip by the record tail
The chunk-continuation queue-limit rejection accounted its stream
consumption and skip from the count-based chunk promise
(chunk_left), but the parser accepts file_len < count and the
tracker only ever consumes file_len bytes. With count > file_len
the consume/skip ran past the record's actual tail into the
following RPC record and the stream desynced.

Consume/skip from the record's unbuffered tail plus the record's
XDR padding.

Ticket: #8791.
1 month ago
Victor Julien 36e8ff5082 nfs: rework and cap the OOO gap backstop to the queue limits
Rework the queue-limit gap backstop: fall back to a 1 GiB / 1024
chunk hard cap when the limits are disabled, run it ahead of the
chunk_left == 0 early return, and scan every open file tx in the
direction (an interleaved handle can hide a first file's queue).
TruncatedFileData is attributed to the truncated tx.

Ticket: #8791.
1 month ago
Victor Julien 3a37959005 nfs: enforce the OOO queue limits on the chunk path
The chunk path (filetracker_update) enqueued per-segment data with no
queue limit. Check the limits on every enqueuing path, projected onto
actual queue growth: only OOO data at a new offset grows the queue,
and only a new OOO chunk adds a map entry. Overflow raises the queue
event on the affected tx and skips to the record boundary.

Replace the 2 MiB gap backstop with a queue-limit one (the chunk-count
cap and all-open-file scan come next), and tag the session gapped on
every gap (even one fully covered by a skip), since the backstop is
gated on that flag. Rejected and evicted tx now release their file
resources so the file logger can clean them up.

Ticket: #8791.
1 month ago
Victor Julien 29a5370e71 nfs: validate WRITE and READ records sizes
Replace the hardcoded 16 MiB record caps with configurable
max-{write,read}-size and observable events: an oversized WRITE
request or READ response is rejected, logged, and its payload skipped
to keep the stream in sync. 0 disables the check.

For v4 records, the issue is more complex due to the COMPOUND type:
A partial v4 COMPOUND record whose frag_len claim is huge must not be
buffered toward that claim (31-bit, attacker-controlled → OOM). The
full parser can't help: on a partial buffer it only returns Incomplete
 ("need more bytes"), with no information about what's coming. The scan
instead walks the buffered prefix's ops by wire extent and reads the
file op's header words alone, answering the gate's four-way question:
 oversized claim detected (reject + skip to the record boundary before
any data buffers), data not yet present (buffer normally), structurall
malformed (bounded rejection), or no oversized op (fall through). It
exists because rejecting before buffering requires the claimed length,
which only a prefix walk can extract.

Ticket: #8791.
1 month ago
Victor Julien b8aeaebcbd nfs: enforce max read/write queue size and count limits
Bound the per-file-transaction OOO queue, mirroring SMB: add
max-{read,write}-queue-{size,cnt} (0 disables, default 64 MiB / 64),
raise a queue event on overflow, and skip the truncated record's
remainder from the stream.

Ticket: #8791.
2 months ago
Victor Julien 9a25b2d93e rust: update ldap parser
Ticket: #8793.
2 months ago
Victor Julien 697b05c12d detect/lua: fix per-thread mem limit disabling
An edge case existed where a lua detect script might fail to reenable
the mem limit after temporarily clearing it to allow for set up. This
would then be persistent for the lifetime of that thread.

Make sure to test these cases before the reset.

Ticket: #8805.
2 months ago
Victor Julien 0c8b4d52c9 lua/dataset: avoid uninitialized pointer use
Uninitialised pointer dereference: lua_newuserdata() returns
uninitialised heap, so s->set contains garbage until :get()
is called. LuaDatasetAdd() then dereferences this wild pointer.

Address by memsetting the whole object.
2 months ago
Victor Julien 82f4883555 lua/datasets: validate string len
Address string size issue: LuaDatasetAdd() fetches a pointer from
lua_tostring(L,2) but takes an independent byte-count from lua_tonumber(L,3)
without comparing it to the real string length.

Check the real string len and pass that along.

Ticket: #8807.
2 months ago
Victor Julien f5ea9e8480 lua/datasets: error on :add before :get
LuaDatasetAdd() dereferenced s->set without ensuring :get had been
called first. The userdata metatable validation it was originally
part of is already in place (Ticket: #8882); what remained is the
missing init check.

Reject :add on an uninitialized dataset. The pointer itself is
zeroed in a follow-up commit.

Ticket: #8882.
2 months ago
Victor Julien e281de36c0 lua/flowvarlib: sanitize length in LuaFlowvarSet()
LuaFlowvarSet() accepted a script-supplied integer for the copy length
without validating it against the actual Lua string length returned by
luaL_checkstring. This could lead to OOB memory access.

This patch checks the length of the string before using it.

Ticket: #8858.
2 months ago
Jeff Lucovsky 46fce26900 ftp: a too-long line drops the rest of the stream slice
Both parse loops stopped as soon as a command or reply reached the
configured maximum length: they advanced the input cursor past the end and
broke out. When that line ended with an LF in the same stream slice it was
already complete, and the bytes behind the LF were ordinary FTP lines that
the break discarded. A segment holding "PORT <long>\r\nQUIT\r\n" lost the
QUIT: it never became a transaction, so inspection and logging never saw
it, and a hidden RETR or PORT never reached AppLayerExpectationCreate,
leaving its data connection unrecognized as ftp-data.

Remove both breaks so the loop continues to the next line. The cursor
assignment goes with them, since nothing reads it once the loop ends, and a
line with no LF still finishes the slice on its own because the getter
zeroes the remaining length.

Removing the breaks is not enough for a line that never reaches the clear.
Truncation was cleared deep inside command and reply handling, which is
skipped for an unrecognized request command, a reply the parser rejects (a
run of spaces, empty once trimmed), or an invalid EPRT/PORT that jumps to
tx_complete. The connection flag then stayed set and the getter dropped the
line behind it as this line's remainder. Snapshot and clear the flag up
front in both loops, for every line whose LF was consumed, so the following
line survives.

Issue: 8884
2 months ago
Philippe Antoine 368bfa6d1f pgsql: fix clippy warning
Fixes fe939e8da7
2 months ago
Philippe Antoine 4fa2843344 jsonschema: sort pgsql properties
Fixes 8b5fb9b044
2 months ago
Victor Julien 2edba88a54 http2: strip padding bytes from PADDED HEADERS/PUSH_PROMISE frames
When the PADDED flag is set on HTTP/2 HEADERS or PUSH_PROMISE frames,
the parser reads the 1-byte Pad Length field but never strips trailing
padding bytes before passing the buffer to the HPACK decoder.

Fix by stripping trailing padding before invoking the HPACK decoder.

Ticket: #8787.
2 months ago
Philippe Antoine 8e5d05f93f http2: improve continuation frame reassembly
by taking into account the flags of the first header frame,
and skip priority and padlength if necessary

Ticket: 8840
2 months ago
Giuseppe Longo ae4341eb5f swf: validate configured depth limits
SWF depth settings were previously limited only to values representable by
uint32_t. This is not sufficient for the buffer-size calculations performed
during SWF decompression.

The decompressed output requires an additional 8-byte FWS header. The
inspection buffer also grows by doubling a uint32_t size, so a required buffer
larger than 2 GiB can cause the growth calculation to wrap.

For LZMA input, a synthesized 13-byte header to the compressed
data is used. The configured compressed-data limit must leave room for this header.

This patch applies the following upper limits:

- decompress-depth: 2147483640 bytes
  (2 GiB minus the 8-byte FWS header)
- compress-depth: 4294967282 bytes
  (UINT32_MAX minus the 13-byte LZMA header

Ticket: #8914
2 months ago
Giuseppe Longo e707b21e21 swf: ignore FileLength when sizing output
SWF FileLength was used to determine the decompressed buffer size when
decompress-depth is set to zero, but this field can be manipulated and it can
lead to evasion.

This patch treat FileLength as metadata, the length bytes are just copied, and
when decompress-depth is set to 0, a maximum value of 50MB is considered for
the decompressed buffer.

Ticket: #8855
2 months ago
Giuseppe Longo d80d7f75a8 swf: grow lzma output in one decoder pass
The on-demand buffer growth introduced for SWF decompression called
lzma_decompress again from byte zero each time the output buffer filled.
Because lzma-rs can buffer up to a dictionary before writing, a single
SWF could be decoded repeatedly as the buffer grew, amplifying CPU use.

This adds a depth-bounded Rust writer that asks C to grow the inspection
buffer as decompressed bytes are emitted.
This keeps a single lzma-rs stream alive, so the input is decoded only once.

Ticket: #8829
2 months ago
Giuseppe Longo ddc6d29fd1 swf: grow decompression buffer on demand
Previously, SWF decompression guessed the final output size from FileLength,
allocated the whole buffer, and then decompressed once. A malicious SWF could
claim a 50MB output and force the per-thread inspection buffer to allocate and
retain 64 MiB before the compressed data was even checked.

Change the logic:
allocate 4 KiB, decompress, grow only when the buffer is full, and continue.
The buffer grows geometrically up to the configured output limit,
and the final inspection length is set to the number of bytes actually produced.

Also, for zlib, Z_OK does not by itself mean that decompression is complete.
It should be checked together with avail_out and avail_in,
grow the buffer when output space is exhausted, and continue the same inflate stream.

Ticket: #8829
2 months ago
Victor Julien 4ca3ec5918 respond/reject: guard Ethernet setup against non-Ethernet packets
When running with --reject-dev in autofp mode, the libnet context is
cached thread-locally and t_inject_mode is latched to LIBNET_LINK on the
first reject for an Ethernet packet. Subsequent rejects from different
interfaces that hit the fast path reuse the cached ctx but incorrectly
still call SetupEthernet(), which dereferences PacketGetEthernet() causing
a crash.

To address this check for if a packet is ethernet in all entry points.

Ticket: #8832.
2 months ago
Victor Julien f93d40bade nfs: fix allocation check in LAYOUTGET fh_handles
The check was too weak: it allowed fh_handles far beyond what fits
in the remaining input, letting a crafted packet drive a large
Vec::with_capacity preallocation in nom7 count().

Bound fh_handles by the remaining input size and by 4096, the
maximum file layout stripe count used by the Linux kernel
(NFS4_PNFS_MAX_STRIPE_CNT).

Ticket: #8816.
2 months ago
Victor Julien 8305ac3028 path: fix traversal check on Windows
On Windows the traversal logic only matched the literal "..\", but
Windows accepts "/" as well.

Fix SCPathContainsTraversal() on Windows to check both "..\\" and "../".

Ticket: #8830.
2 months ago
Victor Julien 29c98799e8 stream: tcp: fix AddAndRotate NULL deref with max-syn-queued 1
AddAndRotate() assumes the SYN queue has at least two elements when
evicting the oldest to make room for a new one. With stream.max-syn-queued
set to 1 this would not be true leading to crash.

Ticket: #8833.
2 months ago
Victor Julien 26d6410d16 log/tcp-data: replace BUG_ON with graceful error handling
Replace the BUG_ON with proper error handling so that any fopen() failure
logs a warning and skips the chunk instead of causing a crash.

Adds a few more warnings for error conditions.

Ticket: #8823.
2 months ago
Victor Julien 710fbb81a5 pcap/log: expand buffer before write in PcapLogSegmentCallback
Segment logging could create larger buffers than the thread buffer
available, which would be silently truncated. However the length passed
to libpcap was still of the non-truncated size, so this would lead
libpcap to read past the end of the buffer.

Fix by trying to expand the buffer as needed.

Ticket: #8835.
2 months ago