owasp-modsecurity / owasp-modsecurity/ModSecurity
Review and document multi-threading support and limitations
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 9.8k
- Forks
- 1.8k
- Avg merge
- 2h 46m
- Merged PRs (30d)
- 1
Description
The goal of this issue is to collect and centralize information about multi-threading support of the current version of modSecurity , as the topic has come up in a number of issues and there are documented guidelines about usage in this context.
Multi-threading support
The library is expected to work in multi-threaded scenarios, as stated in #1726. This means that any issues should be related to incorrect usage or bugs in the current implementation.
"The modSecurity life cycle is divided into different stages. The stage that the rules are loaded is not threading safe by design. (...) Once the rules are loaded multiple requests can share the same RulesSet object, leading to parallelism while addressing different requests in different processes or threads." (Source: #2536, here)
Notes
Operator&Action(includingTransformation) objects are created in the first stage, when rules are loaded and parsed, so their initialization is not synchronized. If their evaluation updates internal state, this needs to be protected to prevent issues in multithreaded contexts.
Examples
The repository currently includes an example of usage of the library in a multi-threaded context, see reading_logs_via_rule_message in the examples directory.
Potential issues/limitations
- Shared files (audit or debug log) potential deadlock or incorrect behaviour on non-Windows platforms
- NOTE: This has not been reproduced or reported as an issue, but is documented here as discussed in the context of a similar issue in the Windows port.
- A deadlock using shared files was found in the initial port of the library to Windows (#3132) which was addressed in #3210.
- The PR discussion mentions the possibility of a similar issue (or other incorrect behaviour) happening in non-Unix platforms due to the use of the
F_SETLKWfcntlto lock the shared files. - The library previously used a mutex (using shared memory to make it available to other processes in a multi-process context), but this was replaced by the
F_SETLKWfcntlin commit 3d20304 due to an unlocking issue under heavy load using nginx, where an acquired lock would not be released when the process was killed. - A possible way to address this would be to go back to the mutex (plus shared memory) implementation but using the robust mutex feature in pthreads, that when a process terminates while holding the mutex notifies the next acquirer of this situation with the
EOWNERDEADreturn value, which allows it to recover the mutex and make it 'consistent' (see PTHREAD_MUTEX_ROBUST).
Reviewed/addressed issues
- InMemoryPerProcess potential issues in multi-threading scenarios
- This has been reported in #3054 and points to the fact that the InMemoryPerProcess class has incorrect locking of its resources, as it only protects updates to the structures but not reads, which would generate undefined behaviour if a thread was updating the structure and then at the same time another threads tries to read the structure.
- This has been addressed in PR #3216.
MODSEC_MUTEX_ON_PMdefine &--enable-mutex-on-pmconfigure flag- The Pm operator includes an optional mutex when accessing
acmptrees. - This was introduced in commit 119a6fc & 7d786b3 likely because of issue #1573.
- This option is off by default and it's not clear whether it's necessary, as stated here.
- The need for this optional lock was reviewed and confirmed not to be necessary.
- Removed in PR #3227.
- The Pm operator includes an optional mutex when accessing
string.h'sascTimeusesstd::ctime, which is not safe in multi-threaded contexts- From IBM's ctime documentation:
- The asctime() and ctime() functions, and other time functions can use a common, statically allocated buffer to hold the return string. Each call to one of these functions might destroy the result of the previous call. The asctime_r(), ctime_r(), gmtime_r(), and localtime_r() functions do not use a common, statically allocated buffer to hold the return string. These functions can be used in place of asctime(), ctime(), gmtime(), and localtime() if reentrancy is desired.
ascTimeis used byTransaction::toJSON, which is used to log transactions.- This was reported by sonarcloud while working on PR #3222:
Non-reentrant POSIX functions should be replaced with their reentrant versions cpp:S1912
- This has been addressed in PR #3228.
- From IBM's ctime documentation:
Misc
- The
unit_testprogram has support to run the operator/transformation tests in a multi-threaded context (launching 50 threads and running each test 5000 times).- The goal is to check if the evaluation of the operator/transformation triggers an issue or unexpected result.
- Notice that allocation & initialization of the operator/transformation is performed in the main thread (as this is done in the stage where rules are loaded, see above).
- This feature was introduced in PR #3221.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the existing multi-threaded example in examples/reading_logs_via_rule_message and the unit_test multi-threaded operator/transformation test support. Compare the documented lifecycle, shared-file concerns, and reviewed/addressed items against the linked implementation notes. Done means the current support, limitations, examples, and already resolved issues are collected and clearly documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- documentation
- Issue type
- Documentation
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100