Skip to content
Snippets Groups Projects
Verified Commit c2063e23 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3457781 by catch, longwave, senscybersecurity, cmlara, cilefen,...

Issue #3457781 by catch, longwave, senscybersecurity, cmlara, cilefen, poker10, greggles, alexpott, ericgsmith, xjm: Maintenance pages leak sensitive environment information

(cherry picked from commit 48b0aea1)
(cherry picked from commit 97118bca)
(cherry picked from commit 3ebfcc89)
parent bba48299
No related branches found
No related tags found
No related merge requests found
Pipeline #299367 passed with warnings
Pipeline: drupal

#299394

    Pipeline: drupal

    #299382

      Pipeline: drupal

      #299379

        +1
        ......@@ -147,7 +147,7 @@ function error_displayable($error = NULL) {
        * Non-recoverable fatal errors cannot be logged by Drupal.
        */
        function _drupal_log_error($error, $fatal = FALSE) {
        $is_installer = InstallerKernel::installationAttempted();
        $is_installer = InstallerKernel::installationAttempted() && \Drupal::hasContainer();
        // Backtrace, exception and 'severity_level' are not valid replacement values
        // for t().
        ......@@ -158,7 +158,7 @@ function _drupal_log_error($error, $fatal = FALSE) {
        // When running inside the testing framework, we relay the errors
        // to the tested site by the way of HTTP headers.
        if (DRUPAL_TEST_IN_CHILD_SITE && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) {
        if (defined('DRUPAL_TEST_IN_CHILD_SITE') && DRUPAL_TEST_IN_CHILD_SITE && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) {
        _drupal_error_header($error['@message'], $error['%type'], $error['%function'], $error['%file'], $error['%line']);
        }
        ......@@ -174,7 +174,7 @@ function _drupal_log_error($error, $fatal = FALSE) {
        // implementations to use it.
        \Drupal::logger('php')->log($severity, '%type: @message in %function (line %line of %file) @backtrace_string.', $error + ['backtrace' => $backtrace, 'exception' => $exception, 'severity_level' => $severity]);
        }
        catch (\Exception $e) {
        catch (\Throwable) {
        // We can't log, for example because the database connection is not
        // available. At least try to log to PHP error log.
        error_log(strtr('Failed to log error: ' . Error::DEFAULT_ERROR_MESSAGE . ' @backtrace_string', $error));
        ......@@ -223,12 +223,16 @@ function _drupal_log_error($error, $fatal = FALSE) {
        }
        // Attempt to reduce verbosity by removing DRUPAL_ROOT from the file path
        // in the message. This does not happen for (false) security.
        if (\Drupal::hasService('kernel')) {
        $root_length = strlen(\Drupal::root());
        if (substr($error['%file'], 0, $root_length) == \Drupal::root()) {
        $error['%file'] = substr($error['%file'], $root_length + 1);
        }
        // in the message. This also prevents full path disclosure, see
        // https://owasp.org/www-community/attacks/Full_Path_Disclosure.
        try {
        $root = \Drupal::root();
        }
        catch (\Throwable) {
        $root = realpath(dirname(__DIR__, 2));
        }
        if (str_starts_with($error['%file'], $root)) {
        $error['%file'] = substr($error['%file'], strlen($root) + 1);
        }
        // Check if verbose error reporting is on.
        ......@@ -244,14 +248,13 @@ function _drupal_log_error($error, $fatal = FALSE) {
        }
        else {
        // With verbose logging, we will also include a backtrace.
        // First trace is the error itself, already contained in the message.
        // While the second trace is the error source and also contained in the
        // message, the message doesn't contain argument values, so we output it
        // once more in the backtrace.
        array_shift($backtrace);
        // Generate a backtrace containing only scalar argument values.
        $error['@backtrace'] = Error::formatBacktrace($backtrace);
        // Strip arguments from the backtrace.
        $error['@backtrace'] = Error::formatBacktrace(array_map(function ($trace) {
        unset($trace['args']);
        return $trace;
        }, $backtrace));
        $message = new FormattableMarkup('<details class="error-with-backtrace"><summary>' . Error::DEFAULT_ERROR_MESSAGE . '</summary><pre class="backtrace">@backtrace</pre></details>', $error);
        }
        }
        ......@@ -268,8 +271,13 @@ function _drupal_log_error($error, $fatal = FALSE) {
        '#title' => 'Error',
        '#markup' => $message,
        ];
        install_display_output($output, $GLOBALS['install_state']);
        exit;
        try {
        install_display_output($output, $GLOBALS['install_state']);
        exit;
        }
        catch (\Throwable) {
        // The maintenance page failed, so fall back to a plain error message.
        }
        }
        $response->setContent($message);
        ......
        ......@@ -43,6 +43,11 @@
        exit();
        }
        // Set the Drupal custom error handler.
        require_once $root_path . '/core/includes/errors.inc';
        set_error_handler('_drupal_error_handler');
        set_exception_handler('_drupal_exception_handler');
        // Start the installer.
        require_once $root_path . '/core/includes/install.core.inc';
        install_drupal($class_loader);
        ......@@ -68,4 +68,21 @@ public function testFileTransferHooks() {
        $this->assertSession()->responseContains('core/misc/states.js');
        }
        /**
        * Tests error handling in authorize.php.
        */
        public function testError(): void {
        $settings_filename = $this->siteDirectory . '/settings.php';
        chmod($settings_filename, 0777);
        $settings_php = file_get_contents($settings_filename);
        $settings_php .= "\ndefine('SIMPLETEST_COLLECT_ERRORS', FALSE);\n";
        $settings_php .= "\ntrigger_error('Test warning', E_USER_WARNING);\n";
        file_put_contents($settings_filename, $settings_php);
        $this->drupalGetAuthorizePHP();
        $this->assertSession()->pageTextContains('User warning: Test warning');
        $this->assertSession()->pageTextMatches('@line \d+ of sites/simpletest@');
        }
        }
        0% Loading or .
        You are about to add 0 people to the discussion. Proceed with caution.
        Finish editing this message first!
        Please register or to comment