1248 Commits

Author SHA1 Message Date
Eduardo Arias
727f2bf840 Perform CssDecode transformation in-place
- Removed inplace helper function from the class, as it's only
  referenced by the implementation.
2024-08-27 10:00:17 -03:00
Eduardo Arias
e687140d05 Perform HexDecode transformation in-place
- Removed inplace helper function from the class, as it's only
  referenced by the implementation.
2024-08-27 10:00:17 -03:00
Eduardo Arias
4670710376 Perform LowerCase & UpperCase transformations in-place
- Refactored to share implementation and reduce code duplication.
2024-08-27 10:00:17 -03:00
Eduardo Arias
fd8a979463 Perform SqlHexDecode transformation in-place
- Validate buffer size before accessing data. The previous
  implementation would only check that there was a character available
  in the buffer but could continue processing/reading characters from
  an hex representation without checking bounds.
- Removed inplace & mytolower helper functions from the class, as
  they're only referenced by the implementation.
- Removed duplicate VALID_HEX & ISODIGIT macros, already in
  src/utils/string.h.
2024-08-27 10:00:17 -03:00
Eduardo Arias
2915ee60e2 Perform Trim, TrimLeft & TrimRight transformations in-place 2024-08-27 10:00:17 -03:00
Eduardo Arias
74d150c068 Perform RemoveCommentsChar, RemoveComments & ReplaceComments transformations in-place 2024-08-27 10:00:17 -03:00
Eduardo Arias
da775eca81 Perform ReplaceNulls transformation in-place 2024-08-27 10:00:17 -03:00
Eduardo Arias
1505025990 Perform RemoveNulls & RemoveWhitespace transformations in-place
- Refactored to share implementation.
2024-08-27 10:00:17 -03:00
Eduardo Arias
1236d9a7cd Perform CompressWhitespace transformation in-place 2024-08-27 10:00:17 -03:00
Eduardo Arias
13203ae5e7 Perform CmdLine transformation in-place 2024-08-27 10:00:17 -03:00
Eduardo Arias
3ff72fbbc5 Perform ParityEven7bit, ParityOdd7bit & ParityZero7bit transformations in-place
- Refactored to share implementations of ParityEven7bit & ParityOdd7bit.
2024-08-27 10:00:17 -03:00
Eduardo Arias
5d39890783 Updated Transformation::evaluate signature to allow for in-place updates, removing unnecessary heap allocated copies.
- Renamed Transformation::evaluate to Transformation::transform to avoid
  confusion with Action's overload methods.
- Updated Transformation::transform signature to receive the value by
  reference and perform the transformation inline, if possible.
  - Some transformations still need to use a temporary std::string to
    perform their work, and then copy the result back.
- Made Transformation::transform methods const and updated Transaction
  parameter to be const.
  - Transaction parameter could not be removed because it's used by just
    a single transformation, UrlDecodeUni.
- Removed std::string Action::evaluate(const std::string &exp,
  Transaction *transaction); which was only implemented by
  Transformation but was not used from the base class, but only after
  downcasting to Transformation, so it can just be declared there (and
  not pollute other actions with a default member implementation -that
  does nothing- which is never called).
2024-08-27 10:00:17 -03:00
David Kirstein
315b3d6e77
Lua::run: Move logging of str parameter to higher log level. 2024-08-26 08:38:48 +02:00
Ervin Hegedus
b4f52325bd
Merge pull request #3228 from eduar-hte/asctime-multithread
Replace usage of std::ctime, which is not safe in multithread contexts
2024-08-14 14:55:53 +02:00
Ervin Hegedus
554bd30e74
Merge pull request #3227 from eduar-hte/pm-operator-multithreading
Removed unnecessary lock to call acmp_process_quick in Pm::evaluate
2024-08-14 12:36:54 +02:00
Ervin Hegedus
a6b287e120
Merge pull request #3225 from airween/v3/mpinvcharreqbody
feat: Check if the MP header contains invalid character
2024-08-14 09:06:14 +02:00
Eduardo Arias
23a341eb6a Calculate sizes of strftime buffers based on format strings
- Leverage std::size to determine buffer size at compile time.
- Simplified 'TimeMon::evaluate' implementation as it was using strftime
  to get the month, convert the string to int, and then decrement it by
  one to make it zero based. This same value is already available in
  the 'struct tm' previously generated with the call to localtime_r (and
  where the month is already zero-based)
2024-08-13 13:36:03 -07:00
Eduardo Arias
5e6fcbc60b Replace usage of std::ctime, which is not safe for use in multithreaded contexts
- std::ctime returns a pointer to a string that "may be shared between
  std::asctime and std::ctime, and may be overwritten on each invocation
  of any of those functions.".
  - https://en.cppreference.com/w/cpp/chrono/c/ctime
- Replaced with call to strftime to generate the same string
  representation (using the format string: %c)
- Leveraged localtime_r (which is thread-safe) to convert time_t to
  struct tm, as required by strftime.
2024-08-13 10:54:06 -07:00
Eduardo Arias
8d6b185856 Removed unnecessary lock to call acmp_process_quick in Pm::evaluate
- This was introduced in commit 119a6fc & 7d786b3 because of a potential
  issue reported in #1573.
- The ACMP tree structure is initialized when the operator is
  initialized.
- During transaction execution the ACMP tree structure is only 'read'
  while traversing the tree (in acmp_process_quick) so this is safe for
  use in a multi-threaded environment.
2024-08-13 10:53:15 -07:00
Ervin Hegedus
718d121ee3
Merge pull request #3216 from eduar-hte/inmemory-collection-shared-mutex
Prevent concurrent access to data in InMemoryPerProcess' resolveXXX methods
2024-08-13 19:30:14 +02:00
Ervin Hegedus
6388d88f38
Check if the MP header contains invalid character 2024-08-13 18:26:18 +02:00
Eduardo Arias
77adb57524 Avoid std::string copy in ssplit argument
- Other minor changes reported by sonarcloud
2024-08-12 12:59:28 -07:00
Eduardo Arias
cc0f893854 Removed unused overload of dash_if_empty that sonarcloud flags as potential buffer overflow 2024-08-09 14:07:39 -07:00
Eduardo Arias
8b17f3691f Inline string functions 2024-08-09 13:21:46 -07:00
Eduardo Arias
1534ee2448 Removed unnecessary copies 2024-08-09 12:52:25 -07:00
eduar-hte
f8dd09f7c9 Avoid creating a new std::string on the heap to create VariableValue
- Introduced helper method addVariableOrigin to reduce code duplication.
2024-08-09 12:52:25 -07:00
Eduardo Arias
bb07de9ad7 toupper/tolower is already receiving a copy, so it doesn't need to create a new one to transform it
- Make functions inline to improve performance
- Introduced helper method toCaseHelper to remove code duplication
2024-08-09 12:52:25 -07:00
Eduardo Arias
293cd214c7 Removed usage of pthreads and replaced with std C++ features
- Replaced pthread_mutex_t in modsecurity::operators::Pm with std::mutex
- Replaced pthread's thread usage in reading_logs_via_rule_message
  example with std::thread.
  - Simplified and modernized C++ code.
- Removed unnecessary includes of pthread.h
2024-08-09 11:34:40 -07:00
Eduardo Arias
e2b3c9594f Prevent concurrent access to data structure in resolve methods
- As reported in #3054, the resolve methods in InMemoryPerProcess are
  not acquiring a lock/mutex to prevent concurrent access to the data
  structures that may be modified at the same time from other threads,
  and thus triggering undefined behaviour.
- Replace inheritance of std::unordered_multimap data structure with
  data member to prevent potential clients to use it without acquiring
  the mutex to protect concurrent access.
- Replace pthreads lock with std C++11 std::shared_mutex
  - Provides exclusive/shared lock access so that multiple readers can
    access the data at the same time, but only one writer. this is used
    to favor query performance by allowing more concurrent access to the
    data until an update needs to be performed.
  - Simplifies acquisition and disposal of lock/mutex with
    std::lock_guard, which has RAII semantics.
  - NOTE: Because std::shared_mutex is not recursive, calls to another
    function that tries to acquire the lock will fail. Introduced
    __store & __updateFirst helper methods to workaround this.
- Updates to InMemoryPerProcess::resolveFirst
  - Updated the code to store the expired var in 'expiredVars' to delete
    them after iterating over the range (and releasing the read lock, as
    'delIfExpired' needs to acquire it for exclusive access), as the
    current call to 'delIfExpired' would invalidate the range triggering
    undefined behaviour on the following iteration.
  - Noticed that in commit 118e1b3 the call to 'delIfExpired' in this
    function is done using 'it->second.getValue()'' instead of
    'it->first', which seems incorrect (based on similar code in other
    resolveXXX functions).
- Updated InMemoryPerProcess::delIfExpired to use 'std::find_if' (with a
  lambda that matches both the key and the 'isExpired' condition)
  because the data structure is a multimap. The version introduced in
  commit 118e1b3 could find an entry (not necessarily the first, because
  the map is unordered) where 'isExpired' is 'false' and exit, while
  another entry could be expired.
2024-08-09 11:34:40 -07:00
Ervin Hegedus
7bdc3c825c
Merge pull request #3220 from eduar-hte/string-null
Creating a std::string with a null pointer is undefined behaviour
2024-08-09 17:37:47 +02:00
Ervin Hegedus
3a83196a71
Merge pull request #3219 from eduar-hte/cpp17
Simplifiy configuration to build using std C++17
2024-08-09 17:34:02 +02:00
Eduardo Arias
c917d6a2dc Initialize variable in if statement to avoid doing dynamic_cast twice
- Refactored duplicate code in RuleWithOperator::getVariablesExceptions
- Leveraged auto to simplify declaration of dynamic_cast pointers.
2024-08-08 13:37:23 -07:00
Eduardo Arias
18378c10f8 Removed unnecessary dynamic_casts 2024-08-08 13:04:29 -07:00
Eduardo Arias
30a68de92d Creating a std::string with a null pointer is undefined behaviour.
- cppreference mentions this about the constructor that receives a
  const char *:
  - Constructs the string with the contents initialized with a copy of
    the null-terminated character string pointed to by s. The length of
    the string is determined by the first null character. The behavior
    is undefined if [s, s + Traits::length(s)) is not a valid range
    (for example, if s is a null pointer).
- C++23 introduces a deleted constructor to prevent this in static
  scenarios, which is how this issue was detected.
2024-08-08 11:39:37 -07:00
Eduardo Arias
59254fe3bd Simplifiy configuration to build libModSecurity with std C++17
- Leveraged autoconf again to check whether the C++ compiler supports
  the required standard version and build using it.
- Replaced the outdaded `ax_cxx_compile_stdcxx_11.m4` macro with the
  latest version of `ax_cxx_compile_stdcxx` which supports C++17.
  - https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
  - https://raw.githubusercontent.com/autoconf-archive/autoconf-archive/e4e5269db2764b9f53d759c24750ac6ca38e02ea/m4/ax_cxx_compile_stdcxx.m4
- This should also streamline updating to C++20 in the future.
2024-08-08 11:23:35 -07:00
Ervin Hegedus
a519c65902
Merge pull request #3217 from gberkes/v3/sonarcloud_Replace_this_declaration_by_a_structured_binding_declaration
V3/sonarcloud replace this declaration by a structured binding declaration
2024-08-08 17:55:09 +02:00
Ervin Hegedus
1d6e72e8e2
Merge pull request #3212 from eduar-hte/defensive-intervention
Do not assume ModSecurityIntervention argument to transaction::intervention has been initialized/cleaned
2024-08-08 17:45:34 +02:00
gberkes
c50a397a87 Suppress cppcheck false positive unassignedVariable warning. 2024-08-07 21:05:47 +02:00
gberkes
35e825d643 Refactor: replaced 3 declarations with 3 structured binding declarations.
This syntax is far more expressive and easier to understand than the old one.

Refactor: flipped the conditions in "if (contains[Tag|Msg|Id]( ... " statements
for clearer code.

Refactor: moved "Variable *b" as an init-statement inside "if()" statements for
stricter scope.

Reference: https://sonarcloud.io/project/issues?open=AY8-ff1vm_fzkWiCOtCt&id=owasp-modsecurity_ModSecurity
2024-08-07 17:55:30 +02:00
gberkes
ab78d4af79 Refactor: used the init-statement to declare "pos" inside the if statement.
C++17 introduced a construct to create and initialize a variable within the
condition of if and switch statements, and C++20 added this construct to
range-based for loops. Using this new feature simplifies common code patterns
and helps in giving variables the right scope.

Reference: https://sonarcloud.io/project/issues?open=AZDCieK2zGtqRpL2rnl-&id=owasp-modsecurity_ModSecurity
2024-08-07 13:05:02 +02:00
Eduardo Arias
0b5493d4e7 Minor performance improvements setting up intervention's log
- Initialize `log` temporary value on construction instead of doing
  default initialization and then calling `append`.
- Leverage `std::string_view` to replace `const std::string&` parameters
  in `utils::string::replaceAll` to avoid creating a `std::string`
  object (and associated allocation and copy) for the string literal`%d`
2024-08-06 14:40:45 -07:00
Eduardo Arias
c947f5e40d Do not assume ModSecurityIntervention argument to transaction::intervention has been initialized/cleaned
- Keep m_it->disruptive value and use it as return value to guarantee
  that the value is correct.
  - If m_it->disruptive is false and the 'it' argument has not been
    initialized/cleaned, the function may incorrectly return a non-zero
    value.
- When a disruptive intervention is being reported by the function,
  defensively initialize log & url to NULL if there's no such data to
  provide to the caller.
  - If the caller has not initialized/cleaned those fields in the 'it'
    argument, after returning from transaction::intervention, the user
    can safely read the log & url fields and in all scenarios they'll
    have valid values.
2024-08-06 14:40:45 -07:00
Ervin Hegedus
68d551c5f9
Merge pull request #3210 from eduar-hte/shared-files-deadlock
Fixed shared files deadlock in a multi-threaded Windows application
2024-08-06 17:35:41 +02:00
Eduardo Arias
4b5f719906 Fixed shared files deadlock in a multi-threaded Windows application
- The shared files Windows implementation introduced in PR #3132 works
  in multi-process single-threaded contexts but it doesn't work
  correctly in single-process multi-threaded contexts.
- The issue is that the LockFileEx Win32 function works on a per-handle
  basis.
  - In a multi-process context, each process will have called
    SharedFiles::add_new_handler when initializing the SharedFile and
    obtained a handle, and thus locking will work.
  - When running ModSecurity in a single process using multiple threads,
    the initialization of the SharedFile will happen once and the handle
    will be shared by all threads. Then, if two threads try to write to
    the same shared file concurrently, they may deadlock as one of them
    will lock the file (by calling LockFileEx) and then proceed to write
    to the file. If before writing to the file and unlocking it, another
    thread calls LockFileEx on the same handle, the attempt to write to
    the file will lock generating a deadlock.
- The new implementation replaces usage of LockFileEx/UnlockFileEx with
  a named mutex to lock access to the shared file.
  - A named mutex is used to support multi-process scenarios.
  - The mutex name is generated using the filename to support multiple
    shared files (such as that for the debug and audit logs).
    - This assumes that both process will initialize the SharedFile
      instance using the same filename (which is expected as they'd be
      using the same configuration file)
2024-08-05 13:04:09 -07:00
Eduardo Arias
dab9bb6a11 Added methods to free buffers allocated by ModSecurity APIs
- The following methods are introduced to allow clients of
  libModSecurity that are not able to link and call the C/C++ standard
  library to be able to free the buffers allocated by libModSecurity.
- msc_intervention_cleanup: Frees the buffers in a
  ModSecurityIntervention structure that have been allocated by calls to
  msc_intervention.
- msc_rules_error_cleanup: Frees an error message buffer allocated by
  the msc_rules_xxx functions to detail the condition that triggered
  the error.
2024-08-05 12:18:11 -07:00
gberkes
b4659959cd Refactor: Ensure safe error handling by removing isolated throw; statements.
- SonarCloud analysis identified standalone `throw;` calls without accompanying `try-catch` blocks, used inconsistently as placeholders or for premature termination under specific conditions.
- Removed these `throw;` instances to prevent potential runtime issues in future development phases, where such configurations might inadvertently be created.
- Introduced `assert` statements as a more appropriate mechanism for asserting preconditions in the affected class member functions, ensuring clearer intent and safer code behavior during development.
- Refactor action_kind processing to use switch() instead of if-else chains; add assertion in default case.
- Fix SonarCloud issue: Make this variable a const reference.
https://sonarcloud.io/project/issues?resolved=false&pullRequest=3104&id=owasp-modsecurity_ModSecurity&open=AY8Vpgy4f6U6E7VKL4Cn
2024-08-04 22:04:07 +02:00
Ervin Hegedus
b6d218f72d
Merge pull request #3116 from gberkes/v3/remove_this_conditional_structure
Deleted redundant code in 'ModSecurity::serverLog(...)'.
2024-08-02 16:33:07 +02:00
Ervin Hegedus
c7efeb6d06
Merge branch 'owasp-modsecurity:v3/master' into v3/sethostname 2024-08-01 22:35:44 +02:00
Ervin Hegedus
4b38435a6e
Merge pull request #3117 from airween/v3/eualrangebyfind
fix: Changed 'equal_range()' + loop by 'find()' in resolveFirst() methods
2024-07-31 15:46:54 +02:00
Ervin Hegedus
937fc5ae59
Provide a function to set 'hostname' field in log 2024-07-29 22:07:26 +02:00