jenkins-bot has submitted this change and it was merged.

Change subject: Add a way to redact certain function parameters from exception 
stack traces
......................................................................


Add a way to redact certain function parameters from exception stack traces

Bug: 30714
Change-Id: I0a9e92448f8d9009dd594cb4d7f5dc6fdd4bcc86
---
M RELEASE-NOTES-1.22
M includes/DefaultSettings.php
M includes/Exception.php
3 files changed, 88 insertions(+), 7 deletions(-)

Approvals:
  Reedy: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/RELEASE-NOTES-1.22 b/RELEASE-NOTES-1.22
index 94a9dfd..3ba86f5 100644
--- a/RELEASE-NOTES-1.22
+++ b/RELEASE-NOTES-1.22
@@ -216,6 +216,8 @@
 * Add deferrable update support for callback/closure
 * Add TitleMove hook before page renames
 * Revision deletion backend code is moved out of SpecialRevisiondelete
+* Add a variable (wgRedactedFunctionArguments) to redact the values sent as 
certain function
+  parameters from exception stack traces.
 
 === Bug fixes in 1.22 ===
 * Disable Special:PasswordReset when $wgEnableEmail is false. Previously one
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index 22b7f1e..51c6c3d 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -4881,6 +4881,37 @@
 $wgShowExceptionDetails = false;
 
 /**
+ * Array of functions which need parameters redacted from stack traces shown to
+ * clients and logged. Keys are in the format '[class::]function', and the
+ * values should be either an integer or an array of integers. These are the
+ * indexes of the parameters which need to be kept secret.
+ * @since 1.22
+ */
+$wgRedactedFunctionArguments = array(
+       'AuthPlugin::setPassword' => 1,
+       'AuthPlugin::authenticate' => 1,
+       'AuthPlugin::addUser' => 1,
+
+       'DatabaseBase::__construct' => 2,
+       'DatabaseBase::open' => 2,
+
+       'SpecialChangeEmail::attemptChange' => 1,
+       'SpecialChangePassword::attemptReset' => 0,
+
+       'User::setPassword' => 0,
+       'User::setInternalPassword' => 0,
+       'User::checkPassword' => 0,
+       'User::setNewpassword' => 0,
+       'User::comparePasswords' => array( 0, 1 ),
+       'User::checkTemporaryPassword' => 0,
+       'User::setToken' => 0,
+       'User::crypt' => 0,
+       'User::oldCrypt' => 0,
+       'User::getPasswordValidity' => 0,
+       'User::isValidPassword' => 0,
+);
+
+/**
  * If true, show a backtrace for database errors
  */
 $wgShowDBErrorBacktrace = false;
diff --git a/includes/Exception.php b/includes/Exception.php
index e1bfb2d..39fe6f4 100644
--- a/includes/Exception.php
+++ b/includes/Exception.php
@@ -127,7 +127,7 @@
 
                if ( $wgShowExceptionDetails ) {
                        return '<p>' . nl2br( htmlspecialchars( 
$this->getMessage() ) ) .
-                               '</p><p>Backtrace:</p><p>' . nl2br( 
htmlspecialchars( $this->getTraceAsString() ) ) .
+                               '</p><p>Backtrace:</p><p>' . nl2br( 
htmlspecialchars( MWExceptionHandler::formatRedactedTrace( $this ) ) ) .
                                "</p>\n";
                } else {
                        return "<div class=\"errorbox\">" .
@@ -152,7 +152,7 @@
 
                if ( $wgShowExceptionDetails ) {
                        return $this->getMessage() .
-                               "\nBacktrace:\n" . $this->getTraceAsString() . 
"\n";
+                               "\nBacktrace:\n" . 
MWExceptionHandler::formatRedactedTrace( $this ) . "\n";
                } else {
                        return "Set \$wgShowExceptionDetails = true; " .
                                "in LocalSettings.php to show detailed 
debugging information.\n";
@@ -275,7 +275,7 @@
                $log = $this->getLogMessage();
                if ( $log ) {
                        if ( $wgLogExceptionBacktrace ) {
-                               wfDebugLog( 'exception', $log . "\n" . 
$this->getTraceAsString() . "\n" );
+                               wfDebugLog( 'exception', $log . "\n" . 
MWExceptionHandler::formatRedactedTrace( $this ) . "\n" );
                        } else {
                                wfDebugLog( 'exception', $log );
                        }
@@ -633,7 +633,7 @@
                                $message = "MediaWiki internal error.\n\n";
 
                                if ( $wgShowExceptionDetails ) {
-                                       $message .= 'Original exception: ' . 
$e->__toString() . "\n\n" .
+                                       $message .= 'Original exception: ' . 
self::formatRedactedTrace( $e ) . "\n\n" .
                                                'Exception caught inside 
exception handler: ' . $e2->__toString();
                                } else {
                                        $message .= "Exception caught inside 
exception handler.\n\n" .
@@ -650,11 +650,10 @@
                                }
                        }
                } else {
-                       $message = "Unexpected non-MediaWiki exception 
encountered, of type \"" . get_class( $e ) . "\"\n" .
-                               $e->__toString() . "\n";
+                       $message = "Unexpected non-MediaWiki exception 
encountered, of type \"" . get_class( $e ) . "\"";
 
                        if ( $wgShowExceptionDetails ) {
-                               $message .= "\n" . $e->getTraceAsString() . 
"\n";
+                               $message .= "\nexception '" . get_class( $e ) . 
"' in " . $e->getFile() . ":" . $e->getLine() . "\nStack trace:\n" . 
self::formatRedactedTrace( $e ) . "\n";
                        }
 
                        if ( $cmdLine ) {
@@ -709,4 +708,53 @@
                // Exit value should be nonzero for the benefit of shell jobs
                exit( 1 );
        }
+
+       /**
+        * Get the stack trace from the exception as a string, redacting 
certain function arguments in the process
+        * @param Exception $e The exception
+        * @return string The stack trace as a string
+        */
+       public static function formatRedactedTrace( Exception $e ) {
+               global $wgRedactedFunctionArguments;
+               $finalExceptionText = '';
+
+               foreach ( $e->getTrace() as $i => $call ) {
+                       $checkFor = array();
+                       if ( isset( $call['class'] ) ) {
+                               $checkFor[] = $call['class'] . '::' . 
$call['function'];
+                               foreach ( class_parents( $call['class'] ) as 
$parent ) {
+                                       $checkFor[] = $parent . '::' . 
$call['function'];
+                               }
+                       } else {
+                               $checkFor[] = $call['function'];
+                       }
+
+                       foreach ( $checkFor as $check ) {
+                               if ( isset( 
$wgRedactedFunctionArguments[$check] ) ) {
+                                       foreach ( 
(array)$wgRedactedFunctionArguments[$check] as $argNo ) {
+                                               $call['args'][$argNo] = 
'REDACTED';
+                                       }
+                               }
+                       }
+
+                       $finalExceptionText .= "#{$i} 
{$call['file']}({$call['line']}): ";
+                       if ( isset( $call['class'] ) ) {
+                               $finalExceptionText .= $call['class'] . 
$call['type'] . $call['function'];
+                       } else {
+                               $finalExceptionText .= $call['function'];
+                       }
+                       $args = array();
+                       foreach ( $call['args'] as $arg ) {
+                               if ( is_object( $arg ) ) {
+                                       $args[] = 'Object(' . get_class( $arg ) 
. ')';
+                               } elseif( is_array( $arg ) ) {
+                                       $args[] = 'Array';
+                               } else {
+                                       $args[] = var_export( $arg, true );
+                               }
+                       }
+                       $finalExceptionText .=  '(' . implode( ', ', $args ) . 
")\n";
+               }
+               return $finalExceptionText . '#' . ( $i + 1 ) . ' {main}';
+       }
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/64450
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I0a9e92448f8d9009dd594cb4d7f5dc6fdd4bcc86
Gerrit-PatchSet: 11
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Alex Monk <[email protected]>
Gerrit-Reviewer: Alex Monk <[email protected]>
Gerrit-Reviewer: CSteipp <[email protected]>
Gerrit-Reviewer: Chad <[email protected]>
Gerrit-Reviewer: Parent5446 <[email protected]>
Gerrit-Reviewer: Reedy <[email protected]>
Gerrit-Reviewer: jenkins-bot

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to