Skip to content

detect/byte: cache byte values in tx state#15333

Open
jlucovsky wants to merge 2 commits intoOISF:mainfrom
jlucovsky:7801/7
Open

detect/byte: cache byte values in tx state#15333
jlucovsky wants to merge 2 commits intoOISF:mainfrom
jlucovsky:7801/7

Conversation

@jlucovsky
Copy link
Copy Markdown
Contributor

Continuation of #15196

Add per-transaction byte value caching so that variables produced by byte_extract and byte_math persist across buffer and direction boundaries.

Without this change, bidirectional (=>) rules that produce a byte variable in a toserver buffer and consume it in a toclient buffer fail when HTTP/1.1 pipelining creates multiple transactions. All TXs share the same det_ctx->byte_values, and a later TX's toserver inspection clobbers values before an earlier TX's toclient inspection runs.

The fix saves byte values to the per-TX DetectEngineState after extraction, restores them before each content inspection pass, clears them when resetting a TX, and frees the memory when DetectEngineState is destroyed, the transaction is reset, or the DetectEngineThreadCtx is uninitialized.

Link to ticket: https://redmine.openinfosecfoundation.org/issues/7801

Note that the issue described in Redmine ticket 1412 is partially addressed with this work when using bi-directional rules and cross-buffer variables. However, unidirectional rules that have cross-buffer support where the producer has a higher progress value than the consumer will still experience the ordering issue from 1412.

Describe changes:

  • detect-engine-state.c/.h: Add byte_values array to DetectEngineState with save/restore functions, cleared/freed on reset, free on destroy
  • detect-engine-content-inspection.c: Restore cached values at start of inspection, save after byte_extract/byte_math
  • detect-engine.c, detect.h: Track byte_values_len in DetectEngineThreadCtx
  • rust/sys/src/sys.rs: Add new fields to bindgen struct
  • Documentation updates in differences-from-snort.rst, payload-keywords.rst, and devguide/transactions.rst

Updates:

  • Moved from issue 1412 to 7801 as focus is on cross buffer-variable usage
  • Adjust positioning of byte_value variables to reduce holes in struct (see scan-build in detect/byte: cache byte values in tx state #15027)
  • Skip caching for unidirectional rules since all buffers are inspected in a single TX.
  • Clear on engine reload
  • Removed dynamic growth with a single alloc as the size is static.
  • Address review comments (see detect/byte: cache byte values in tx state #15084)
  • Eliminated byte values swap and use make a memory copy of the values to avoid ownership issues. Added @catenacyber's test case that validates this to s-v PR
  • Created Redmine issue 8458 to handle rules that try to use byte values before they are created.
  • Fix formatting issue
  • Rebase

Provide values to any of the below to override the defaults.

  • To use a Suricata-Verify or Suricata-Update pull request,
    link to the pull request in the respective _BRANCH variable.
  • Leave unused overrides blank or remove.

SV_REPO=
SV_BRANCH=OISF/suricata-verify#2968
SU_REPO=
SU_BRANCH=

jlucovsky added 2 commits May 7, 2026 09:20
det_ctx->byte_values is shared across every transaction a worker touches.
Once an inspect engine finishes for a signature, its ID is recorded in
inspect_flags and it won't run again when the rule resumes on a later
packet. That means a value produced by byte_extract or byte_math can get
clobbered by another transaction before the consumer buffer ever runs.

Store produced values in a byte_values array on the per-TX
DetectEngineState to fix this:

- Save to the TX cache after byte_extract or byte_math succeeds.
- Copy (memcpy) into det_ctx->byte_values at the start of each content
  inspection pass (recursion.count == 0).
- Free the TX cache on detect engine reload -- local IDs can change with
  a new ruleset, so the next save reallocates at the right size.
- Free on state destruction.

Document the cache in devguide/transactions.rst.

Issue: 7801
byte_extract and byte_math values can now be used in a different buffer
or direction than where they were produced, as long as the producing
buffer has a lower progress value than the consuming buffer -- progress
order is what determines which buffer gets inspected first.

- differences-from-snort: drop the paragraph noting that cross-buffer
  byte variable usage was unsupported
- payload-keywords: add cross-buffer notes and an example to the
  byte_extract and byte_math sections

Issue: 7801
@codecov
Copy link
Copy Markdown

codecov Bot commented May 7, 2026

Codecov Report

❌ Patch coverage is 82.75862% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.64%. Comparing base (899e9f0) to head (bf3f80e).

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #15333      +/-   ##
==========================================
- Coverage   82.64%   82.64%   -0.01%     
==========================================
  Files         995      995              
  Lines      271075   271131      +56     
==========================================
+ Hits       224042   224070      +28     
- Misses      47033    47061      +28     
Flag Coverage Δ
fuzzcorpus 61.03% <32.75%> (-0.01%) ⬇️
livemode 18.38% <6.89%> (-0.01%) ⬇️
netns 22.57% <8.62%> (-0.03%) ⬇️
pcap 45.21% <10.34%> (-0.06%) ⬇️
suricata-verify 66.41% <81.03%> (+0.02%) ⬆️
unittests 58.55% <13.79%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@suricata-qa
Copy link
Copy Markdown

WARNING:

field baseline test %
SURI_TLPR1_autofp_suri

Pipeline = 31239

@ct0br0
Copy link
Copy Markdown

ct0br0 commented May 7, 2026

that qa run was bad. rerunning.

@suricata-qa
Copy link
Copy Markdown

Information: QA ran without warnings.

Pipeline = 31244

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants