Origin: https://cgit.drupalcode.org/drupal/rawdiff/?h=7.x&id=080daa38f265ea28444c540832509a48861587d0
Forwarded: not-needed
From: David Rothstein <drothstein@gmail.com>
Date: Wed Apr 25 13:13:59 CDT 2018
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=896701
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2018-7602
Subject: Fixes for SA-CORE-2018-004 (Remote Code Execution)
 Backported the diff between 7.58 and 7.59, applying it to the version in the
 Stable Debian release (7.52). For further details, the advisory is in:
 .
 CVE 2018-7602 - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-7602
 .
 Drupal advisory - https://www.drupal.org/SA-CORE-2018-004

Index: drupal7/includes/bootstrap.inc
===================================================================
--- drupal7.orig/includes/bootstrap.inc
+++ drupal7/includes/bootstrap.inc
@@ -2763,6 +2763,11 @@ function _drupal_bootstrap_variables() {
       unset($_GET['destination']);
       unset($_REQUEST['destination']);
     }
+    // Use the DrupalRequestSanitizer to ensure that the destination's query
+    // parameters are not dangerous.
+    if (isset($_GET['destination'])) {
+      DrupalRequestSanitizer::cleanDestination();
+    }
     // If there's still something in $_REQUEST['destination'] that didn't come
     // from $_GET, check it too.
     if (isset($_REQUEST['destination']) && (!isset($_GET['destination']) || $_REQUEST['destination'] != $_GET['destination']) && url_is_external($_REQUEST['destination'])) {
Index: drupal7/includes/common.inc
===================================================================
--- drupal7.orig/includes/common.inc
+++ drupal7/includes/common.inc
@@ -611,8 +611,9 @@ function drupal_parse_url($url) {
   }
   // The 'q' parameter contains the path of the current page if clean URLs are
   // disabled. It overrides the 'path' of the URL when present, even if clean
-  // URLs are enabled, due to how Apache rewriting rules work.
-  if (isset($options['query']['q'])) {
+  // URLs are enabled, due to how Apache rewriting rules work. The path
+  // parameter must be a string.
+  if (isset($options['query']['q']) && is_string($options['query']['q'])) {
     $options['path'] = $options['query']['q'];
     unset($options['query']['q']);
   }
Index: drupal7/includes/request-sanitizer.inc
===================================================================
--- drupal7.orig/includes/request-sanitizer.inc
+++ drupal7/includes/request-sanitizer.inc
@@ -52,6 +52,38 @@ class DrupalRequestSanitizer {
   }
 
   /**
+   * Removes the destination if it is dangerous.
+   *
+   * Note this can only be called after common.inc has been included.
+   *
+   * @return bool
+   *   TRUE if the destination has been removed from $_GET, FALSE if not.
+   */
+  public static function cleanDestination() {
+    $dangerous_keys = array();
+    $log_sanitized_keys = variable_get('sanitize_input_logging', FALSE);
+
+    $parts = drupal_parse_url($_GET['destination']);
+    // If there is a query string, check its query parameters.
+    if (!empty($parts['query'])) {
+      $whitelist = variable_get('sanitize_input_whitelist', array());
+
+      self::stripDangerousValues($parts['query'], $whitelist, $dangerous_keys);
+      if (!empty($dangerous_keys)) {
+        // The destination is removed rather than sanitized to mirror the
+        // handling of external destinations.
+        unset($_GET['destination']);
+        unset($_REQUEST['destination']);
+        if ($log_sanitized_keys) {
+          trigger_error(format_string('Potentially unsafe destination removed from query string parameters (GET) because it contained the following keys: @keys', array('@keys' => implode(', ', $dangerous_keys))));
+        }
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+
+  /**
    * Strips dangerous keys from the provided input.
    *
    * @param mixed $input
Index: drupal7/modules/file/file.module
===================================================================
--- drupal7.orig/modules/file/file.module
+++ drupal7/modules/file/file.module
@@ -239,6 +239,9 @@ function file_ajax_upload() {
   $form_parents = func_get_args();
   $form_build_id = (string) array_pop($form_parents);
 
+  // Sanitize form parents before using them.
+  $form_parents = array_filter($form_parents, 'element_child');
+
   if (empty($_POST['form_build_id']) || $form_build_id != $_POST['form_build_id']) {
     // Invalid request.
     drupal_set_message(t('An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (@size) that this server supports.', array('@size' => format_size(file_upload_max_size()))), 'error');
