Skip to content

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

Closed
jlucovsky wants to merge 2 commits intoOISF:mainfrom
jlucovsky:7801/6
Closed

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

Conversation

@jlucovsky
Copy link
Copy Markdown
Contributor

Continuation of #15195

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

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

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=

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 Apr 12, 2026

Codecov Report

❌ Patch coverage is 82.75862% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.68%. Comparing base (336b50a) to head (a49d229).
⚠️ Report is 8 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #15196      +/-   ##
==========================================
- Coverage   82.71%   82.68%   -0.03%     
==========================================
  Files         993      993              
  Lines      271737   271809      +72     
==========================================
- Hits       224772   224751      -21     
- Misses      46965    47058      +93     
Flag Coverage Δ
fuzzcorpus 61.06% <32.75%> (-0.06%) ⬇️
livemode 18.33% <6.89%> (-0.04%) ⬇️
netns 22.59% <8.62%> (-0.02%) ⬇️
pcap 45.25% <10.34%> (-0.07%) ⬇️
suricata-verify 66.25% <81.03%> (-0.02%) ⬇️
unittests 58.84% <13.79%> (-0.03%) ⬇️

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_stats_chk
.app_layer.flow.ftp-data 697 664 95.27%

Pipeline = 30908

Comment thread src/detect-engine-state.c
* its own allocation so that values remain correct across multiple
* packets: a pointer swap would rotate ownership on every packet and
* leave each TX reading another TX's values on the second packet. */
memcpy(det_ctx->byte_values, state->byte_values, state->byte_values_size * sizeof(uint64_t));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optimization detail : I think we can do the swap instead of memcpy, if we care to swap back at the right time

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes -- the swap could be reintroduced but note that the amount of the data copied is bounded -- in practice, it's just a few uint64_t's.

@catenacyber
Copy link
Copy Markdown
Contributor

Still questions about tickets and scope :

For the latter, you said

similar problem with a different variable type.

Is it a simple fixup to add ? Or a more complete one

@jlucovsky
Copy link
Copy Markdown
Contributor Author

Still questions about tickets and scope :

  • does this PR solve 1412 as well ?

Test case 09 uses the rule/pcap from the issue 1412.

For the latter, you said

similar problem with a different variable type.

Is it a simple fixup to add ? Or a more complete one

The fix for 7197 is more involved and better handled by a follow-on PR.

@catenacyber
Copy link
Copy Markdown
Contributor

The fix for 7197 is more involved and better handled by a follow-on PR.

OK thanks

  • does this PR solve 1412 as well ?

Test case 09 uses the rule/pcap from the issue 1412.

But the ticket do not mention ticket 1412, is this solved by this PR of is there more to do ?

@jlucovsky
Copy link
Copy Markdown
Contributor Author

The fix for 7197 is more involved and better handled by a follow-on PR.

OK thanks

  • does this PR solve 1412 as well ?

Test case 09 uses the rule/pcap from the issue 1412.

But the ticket do not mention ticket 1412, is this solved by this PR of is there more to do ?

1412 is partially solved -- for bidirectional rules, it's completely solved. For unidirectional rules, if the producing buffer is at a higher progress than the consuming buffer, the issue from 1412 still occurs.

I'll make sure that the PR states this -- i'm rebasing and putting a replacement pr together.

@jlucovsky
Copy link
Copy Markdown
Contributor Author

Continued in #15333

@jlucovsky jlucovsky closed this May 7, 2026
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