About

Perl-Compatible Regular Expressions use recursion in order to process strings using a given regular expression. Depending on whether the regular expression can be arbitrarily chosen by an attacker, a ReDoS could be performed by consuming enough stack that would result in an unavoidable stack overflow - although *nix systems provide configurable limits to prevent such occurrences. The PCRE library is well-aware of the issue of using recursion and provides the ability to compile PCRE to use the heap (under FreeBSD, it is as easy as de-selecting the recursion-related option when recompiling the port); however, the heap is also much slower, especially for string-manipulations where one would hope for speedy results.

In case stack recursion is used, then PCRE conveniently allows the programmer to set the recursion depth. Unfortunately, even wide-spread linkers such as PHP that use PCRE, set the recursion limit to some bogus value that usually oversteps the system-wide stack size limitation. In doing so, this unavoidably leads to PHP overstepping the system-wide stack size limitation which makes the operating system terminate the process.

What the Recursion Depth Should Be

From the official PCRE documentation, the recursion stack memory usage can be determined by using the pcretest utility:

pcretest -m -C

This should yield, amongst others, the memory consumed by a single stack frame during recursion:

Match recursion uses stack: approximate frame size = 496 bytes

to which, the documentation suggests that that about $16$ more bytes should be added.

This means that for every level of the recursion, every stack frame should consume an approximate value of 500 bytes.

Unavoidable Stack Limit Overstep

For libraries or tools that use PCRE, the recursion depth is often set inadequately - for instance, looking at the PHP PCRE documentation, the recursion depth is set by default at $100000$ which would result in the usage of $50000000$ bytes or $\approx 50MB$ that will exceed the system-wide stack size limit on most Linux distributions - to find out, also issue:

ulimit -s

which, usually yields 8192 bytes ($8MB$).

The result is that if PCRE is used by a library or an utility such as PHP to process arbitrary user-input, a well-chosen input could result in overstepping the system-wide stack size limit.

In order to avoid this issue (especially in PHP - where it tends to hurt most), one would issue:

ulimit -s

and jot down the stack size - let's assume that the result is $8192B$; as it is on most end-user Linux systems. Next, issue:

pcretest -m -C

and the last line should give you the frame size as per the previous example.

Inferring a Formula to Calculate an Adequate Recursion Depth Limit

Assuming that the frame size is $\approx 500B$ and that the system-wide stack size limit is $8192B$, then the formula becomes:

\begin{eqnarray*}
\text{Maximal Recursion Depth} $=$ \frac{\text{Stack Size Limit}}{\text{Frame Size}}
\end{eqnarray*}

which, in this example would yield a rounded-down value of $16$ - this value represents the maximal recursion depth that PCRE should be set to.

Increasing the System Stack Size Limit

If the computed recursion depth value is too small, then the only option is to increase the stack size using ulimit.

Settings for PHP

To set the maximal recursion depth for PHP, locate and edit php.ini in order to add or amend the line:

pcre.recursion_limit=16

in this instance, we have set the value to $16$ which is the value computed in the previous example that corresponds to an 8MB system-wide stack size limit.


security/limiting_perl_compatible_regular_expressions_recursion_to_system-wide_stack_size_limits.txt ยท Last modified: 2022/04/19 08:28 by 127.0.0.1

Wizardry and Steamworks

© 2025 Wizardry and Steamworks

Access website using Tor Access website using i2p Wizardry and Steamworks PGP Key


For the contact, copyright, license, warranty and privacy terms for the usage of this website please see the contact, license, privacy, copyright.