Skip to content

fix(collections): Honour SecDataDir for LMDB, fix literal setvar writ…#3597

Open
20vikash wants to merge 1 commit into
owasp-modsecurity:v3/masterfrom
20vikash:lmdb-fix
Open

fix(collections): Honour SecDataDir for LMDB, fix literal setvar writ…#3597
20vikash wants to merge 1 commit into
owasp-modsecurity:v3/masterfrom
20vikash:lmdb-fix

Conversation

@20vikash

Copy link
Copy Markdown

what

  • SecDataDir is now honoured by the LMDB backend. The path is stored in
    RulesSetProperties and used by the MDBEnvProvider singleton to open the LMDB
    environment (data.mdb/lock.mdb) inside that directory. Falls back to the
    legacy "./modsec-shared-collections" file when SecDataDir is unset.

  • SecDataDir misconfiguration is now loud. The parser validates the path
    (exists, is a directory, writable) and fails configuration load on error,
    surfacing the message through getParserError to the connector error log.

  • LMDB open failures are now logged to stderr instead of being silently
    swallowed.

  • Literal setvar targets now persist. set_var.cc only dispatched writes to
    the dynamic variable subclasses. Variables parsed as literal dict elements
    fell through an empty else branch and were never stored. This adds name
    based dispatch for the literal case.

  • Collection variable names are now case-insensitive. The composite key
    compared variable names case-sensitively, so setvar:ip.counter and
    IP:COUNTER resolved to different entries. All Collection wrapper methods now
    lowercase the variable name term.

  • Bison and flex outputs regenerated from the edited grammar.

why

  • SecDataDir is a documented directive shipped in modsecurity.conf-recommended.
    Users expect it to control where persistent collection data lives. In v3
    with LMDB it was a no-op: the value was discarded and the file always
    appeared in the worker current working directory, with no error in the log.

  • The silent setvar no-op was a data loss bug. Any rule writing a literal
    collection variable lost the value with no error. The 2018 RunTimeString
    refactor replaced the original generic dispatcher with per type dynamic
    casts that omitted the literal case by oversight, not by design.

  • Case insensitive variable names are a SecLang property: the scanner matches
    collection prefixes case insensitively. The case sensitive key broke the
    natural pattern of a lowercase write and uppercase read, silently producing
    empty match values. Fixing it at the Collection wrapper boundary covers both
    LMDB and in memory backends.

references

  • Hardcoded LMDB path: lmdb.cc mdb_env_open of "./modsec-shared-collections".
  • setvar literal no-op: set_var.cc dynamic cast dispatch, introduced in
    commit f17af95 "Using RunTimeString on setvar action".
  • Case sensitive keys: collection.h composite key wrappers, lmdb.cc strncmp.
  • modsecurity.conf-recommended line 203 ships "SecDataDir /tmp/".
  • Tests that informed the fix: action-expirevar.json (lowercase write plus
    uppercase read asserted the value), collection-regular_expression_selection
    .json (uppercase setvar only asserted the debug log line, masking the no-op).

related issue

#3394

changed files

Hand edited:

  • headers/modsecurity/rules_set_properties.h
  • headers/modsecurity/collection/collection.h
  • src/parser/seclang-parser.yy
  • src/collection/backend/lmdb.h
  • src/collection/backend/lmdb.cc
  • src/actions/set_var.cc

Regenerated:

  • src/parser/seclang-parser.cc
  • src/parser/seclang-parser.hh
  • src/parser/seclang-scanner.cc

@sonarqubecloud

Copy link
Copy Markdown

@airween

airween commented Jul 10, 2026

Copy link
Copy Markdown
Member

Hi @20vikash,

thanks for this PR.

To be honest, I've been working on this solution for a while (well, I'm almost done), but I want to add that to 4.0, not to 3.0.

I hope I can finish that work soon and can send my PR - I'll let you know when I'm done.

@20vikash

Copy link
Copy Markdown
Author

@airween Hey. Thanks for the reply. Hope to see the full fix in V4. I encountered this silent failure while implementing a basic rate limiter. So, decided to make a quick fix in V3.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants