PHP fatal error related to output buffering in the csrf-magic.php file
-
Received this error from pfsense.
Crash report begins. Anonymous machine information:
amd64
14.0-CURRENT
FreeBSD 14.0-CURRENT amd64 1400094 #1 RELENG_2_7_2-n255948-8d2b56da39c: Wed Dec 6 20:45:47 UTC 2023 root@freebsd:/var/jenkins/workspace/pfSense-CE-snapshots-2_7_2-main/obj/amd64/StdASW5b/var/jenkins/workspace/pfSense-CE-snapshots-2_7_2-main/sources/FCrash report details:
PHP Errors:
[30-Jun-2024 15:45:11 US/Mountain] PHP Fatal error: str_ireplace(): Cannot use output buffering in output buffering display handlers in /usr/local/www/csrf/csrf-magic.php on line 165
[30-Jun-2024 16:05:27 US/Mountain] PHP Fatal error: str_ireplace(): Cannot use output buffering in output buffering display handlers in /usr/local/www/csrf/csrf-magic.php on line 165No FreeBSD crash data found.
Has anyone else seen this issue? ChatGPT 4o suggests the following.
Replace str_ireplace with preg_replace: To resolve this issue, we should ensure no output buffering functions like str_ireplace are used directly within the output buffer handler. This change ensures that output buffering functions are not nested within the output buffer handler, which prevents conflicts and errors.
Original Function:
function csrf_ob_handler($buffer, $flags) {
static $is_html = false;
if (!$is_html) {
if (stripos($buffer, '<html') !== false) {
$is_html = true;
} else {
return $buffer;
}
}
$tokens = csrf_get_tokens();
$name = $GLOBALS['csrf']['input-name'];
$endslash = $GLOBALS['csrf']['xhtml'] ? ' /' : '';
$input = "<input type='hidden' name='$name' value="$tokens"$endslash>";
$buffer = preg_replace('#(<form[^>]method\s=\s*["']post["'][^>]*>)#i', '$1' . $input, $buffer);if ($GLOBALS['csrf']['frame-breaker']) { $buffer = str_ireplace('</head>', '<script type="text/javascript">if (top != self) {top.location.href = self.location.href;}</script></head>', $buffer); } if ($js = $GLOBALS['csrf']['rewrite-js']) { $buffer = str_ireplace( '</head>', '<script type="text/javascript">'. 'var csrfMagicToken = "'.$tokens.'";'. 'var csrfMagicName = "'.$name.'";</script>'. '<script src="'.$js.'" type="text/javascript"></script></head>', $buffer ); $script = '<script type="text/javascript">CsrfMagic.end();</script>'; $buffer = str_ireplace('</body>', $script . '</body>', $buffer, $count); if (!$count) { $buffer .= $script; } } return $buffer;
}
Refactored Function:
function csrf_ob_handler($buffer, $flags) {
static $is_html = false;
if (!$is_html) {
if (stripos($buffer, '<html') !== false) {
$is_html = true;
} else {
return $buffer;
}
}
$tokens = csrf_get_tokens();
$name = $GLOBALS['csrf']['input-name'];
$endslash = $GLOBALS['csrf']['xhtml'] ? ' /' : '';
$input = "<input type='hidden' name='$name' value="$tokens"$endslash>";
$buffer = preg_replace('#(<form[^>]method\s=\s*["']post["'][^>]*>)#i', '$1' . $input, $buffer);if ($GLOBALS['csrf']['frame-breaker']) { $buffer = preg_replace('#</head>#i', '<script type="text/javascript">if (top != self) {top.location.href = self.location.href;}</script></head>', $buffer); } if ($js = $GLOBALS['csrf']['rewrite-js']) { $buffer = preg_replace( '#</head>#i', '<script type="text/javascript">'. 'var csrfMagicToken = "'.$tokens.'";'. 'var csrfMagicName = "'.$name.'";</script>'. '<script src="'.$js.'" type="text/javascript"></script></head>', $buffer ); $script = '<script type="text/javascript">CsrfMagic.end();</script>'; if (stripos($buffer, '</body>') !== false) { $buffer = str_ireplace('</body>', $script . '</body>', $buffer); } else { $buffer .= $script; } } return $buffer;
}
-
Are you using php custom memory limits? They are under advanced options.
-
@JonathanLee Nothing is set so the default size is 512 MiB.
-
@foxhnd do me a favor increase it to 1GB and see if you want test what you were doing again. How much memory do you have available to access? Keep in mind it would use that php memory when it is needed.
-
@JonathanLee I'll try increasing it to 1024 MiB. Plenty of memory, my physical hardware is a Protectli VP2420 with 16GB memory and 4GB swap space. Memory usage usually sits around 6 - 10% normal load on my network. Thank you for the suggestion, I'm still learning this product.
-
@JonathanLee Increasing the PHP Settings to 1024 MiB, seems to have resolved my issue. Thank you!
-
@foxhnd I think it is designed that way to help stop memory overflow attacks. Example if the memory overflows it just errors out with that buffer error, versus attempting to adapt the stack for accessing more memory, they have a limit built in that simply says nope not on my stack and moves on with firewalling. I see that error sometimes when I attempt to look at very large logs but my system only has 4GB ram and I have my php set to 512mb. The things I would do with 16GBs that’s amazing.
Glad it fixed it.
-
@JonathanLee In my case, I was doing something similar. I had two browser tabs open, monitoring Snort alerts on two different LANs to fine-tune Snort. Thanks again.
-
@foxhnd that is the same thing I was doing when I got that error too