[Pkg-drupal-commits] r2156 - in /branches/lenny-security/debian: changelog patches/00list patches/20_SA-CORE-2010-002.dpatch

luigi at users.alioth.debian.org luigi at users.alioth.debian.org
Thu Sep 9 06:43:32 UTC 2010


Author: luigi
Date: Thu Sep  9 06:43:26 2010
New Revision: 2156

URL: http://svn.debian.org/wsvn/pkg-drupal/?sc=1&rev=2156
Log:
Fixes multiple XSS vulnerabilities (Closes: #572439) (Ref: SA-CORE-2010-001, CVE-TBA)

Added:
    branches/lenny-security/debian/patches/20_SA-CORE-2010-002.dpatch   (with props)
Modified:
    branches/lenny-security/debian/changelog
    branches/lenny-security/debian/patches/00list

Modified: branches/lenny-security/debian/changelog
URL: http://svn.debian.org/wsvn/pkg-drupal/branches/lenny-security/debian/changelog?rev=2156&op=diff
==============================================================================
--- branches/lenny-security/debian/changelog (original)
+++ branches/lenny-security/debian/changelog Thu Sep  9 06:43:26 2010
@@ -1,3 +1,12 @@
+drupal6 (6.6-3lenny6) stable-security; urgency=low
+
+  [ Luigi Gangitano ]
+  * debian/patches/20_SA-CORE-2010-002
+    - Fixes multiple XSS vulnerabilities (Closes: #592716)
+      (Ref: SA-CORE-2010-002, CVE-TBA)
+
+ -- Luigi Gangitano <luigi at debian.org>  Thu, 09 Sep 2010 08:40:21 +0200
+
 drupal6 (6.6-3lenny5) stable-security; urgency=high
 
   [ Luigi Gangitano ]

Modified: branches/lenny-security/debian/patches/00list
URL: http://svn.debian.org/wsvn/pkg-drupal/branches/lenny-security/debian/patches/00list?rev=2156&op=diff
==============================================================================
--- branches/lenny-security/debian/patches/00list (original)
+++ branches/lenny-security/debian/patches/00list Thu Sep  9 06:43:26 2010
@@ -7,3 +7,4 @@
 17_SA-CORE-2009-008
 18_SA-CORE-2009-009
 19_SA-CORE-2010-001
+20_SA-CORE-2010-002

Added: branches/lenny-security/debian/patches/20_SA-CORE-2010-002.dpatch
URL: http://svn.debian.org/wsvn/pkg-drupal/branches/lenny-security/debian/patches/20_SA-CORE-2010-002.dpatch?rev=2156&op=file
==============================================================================
--- branches/lenny-security/debian/patches/20_SA-CORE-2010-002.dpatch (added)
+++ branches/lenny-security/debian/patches/20_SA-CORE-2010-002.dpatch Thu Sep  9 06:43:26 2010
@@ -1,0 +1,460 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 20_SA-CORE-2010-002.dpatch by Luigi Gangitano <luigi at debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Fixes multiple vulnerabilities
+
+ at DPATCH@
+diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' lenny~/includes/actions.inc lenny/includes/actions.inc
+--- lenny~/includes/actions.inc	2009-08-05 02:50:58.000000000 +0200
++++ lenny/includes/actions.inc	2010-09-09 08:35:16.000000000 +0200
+@@ -272,7 +272,7 @@
+       else {
+         // This is a new singleton that we don't have an aid for; assign one.
+         db_query("INSERT INTO {actions} (aid, type, callback, parameters, description) VALUES ('%s', '%s', '%s', '%s', '%s')", $callback, $array['type'], $callback, '', $array['description']);
+-        watchdog('actions', "Action '%action' added.", array('%action' => filter_xss_admin($array['description'])));
++        watchdog('actions', "Action '%action' added.", array('%action' => $array['description']));
+       }
+     }
+   }
+@@ -294,7 +294,7 @@
+       $results = db_query("SELECT a.aid, a.description FROM {actions} a WHERE callback IN ($placeholders)", $orphaned);
+       while ($action = db_fetch_object($results)) {
+         actions_delete($action->aid);
+-        watchdog('actions', "Removed orphaned action '%action' from database.", array('%action' => filter_xss_admin($action->description)));
++        watchdog('actions', "Removed orphaned action '%action' from database.", array('%action' => $action->description));
+       }
+     }
+     else {
+diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' lenny~/modules/comment/comment.module lenny/modules/comment/comment.module
+--- lenny~/modules/comment/comment.module	2010-09-09 08:35:13.000000000 +0200
++++ lenny/modules/comment/comment.module	2010-09-09 08:35:16.000000000 +0200
+@@ -663,7 +663,7 @@
+   global $user;
+ 
+   if ($op == 'edit') {
+-    return ($user->uid && $user->uid == $comment->uid && comment_num_replies($comment->cid) == 0) || user_access('administer comments');
++    return ($user->uid && $user->uid == $comment->uid && comment_num_replies($comment->cid) == 0 && $comment->status == COMMENT_PUBLISHED) || user_access('administer comments');
+   }
+ }
+ 
+diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' lenny~/modules/openid/openid.install lenny/modules/openid/openid.install
+--- lenny~/modules/openid/openid.install	2009-08-05 02:51:31.000000000 +0200
++++ lenny/modules/openid/openid.install	2010-09-09 08:35:16.000000000 +0200
+@@ -66,5 +66,80 @@
+     'primary key' => array('assoc_handle'),
+   );
+ 
++  $schema['openid_nonce'] = array(
++    'description' => 'Stores received openid.response_nonce per OpenID endpoint URL to prevent replay attacks.',
++    'fields' => array(
++      'idp_endpoint_uri' => array(
++        'type' => 'varchar',
++        'length' => 255,
++        'description' => 'URI of the OpenID Provider endpoint.',
++      ),
++      'nonce' => array(
++        'type' => 'varchar',
++        'length' => 255,
++        'description' => 'The value of openid.response_nonce'
++      ),
++      'expires' => array(
++        'type' => 'int',
++        'not null' => TRUE,
++        'default' => 0,
++        'description' => 'A Unix timestamp indicating when the entry should expire.',
++      ),
++    ),
++    'indexes' => array(
++      'nonce' => array('nonce'),
++      'expires' => array('expires'),
++    ),
++  );
++
+   return $schema;
+ }
++
++/**
++ * @defgroup updates-6.x-extra Extra openid updates for 6.x
++ * @{
++ */
++
++/**
++ * Add the openid_nonce table.
++ *
++ * Implementation of hook_update_N().
++ */
++function openid_update_6000() {
++  $ret = array();
++
++  $schema['openid_nonce'] = array(
++    'description' => 'Stores received openid.response_nonce per OpenID endpoint URL to prevent replay attacks.',
++    'fields' => array(
++      'idp_endpoint_uri' => array(
++        'type' => 'varchar',
++        'length' => 255,
++        'description' => 'URI of the OpenID Provider endpoint.',
++      ),
++      'nonce' => array(
++        'type' => 'varchar',
++        'length' => 255,
++        'description' => 'The value of openid.response_nonce'
++      ),
++      'expires' => array(
++        'type' => 'int',
++        'not null' => TRUE,
++        'default' => 0,
++        'description' => 'A Unix timestamp indicating when the entry should expire.',
++      ),
++    ),
++    'indexes' => array(
++      'nonce' => array('nonce'),
++      'expires' => array('expires'),
++    ),
++  );
++
++  db_create_table($ret, 'openid_nonce', $schema['openid_nonce']);
++
++  return $ret;
++}
++
++/**
++ * @} End of "defgroup updates-6.x-extra"
++ * The next series of updates should start at 7000.
++ */
+diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' lenny~/modules/openid/openid.module lenny/modules/openid/openid.module
+--- lenny~/modules/openid/openid.module	2010-09-09 08:35:13.000000000 +0200
++++ lenny/modules/openid/openid.module	2010-09-09 08:35:16.000000000 +0200
+@@ -96,7 +96,7 @@
+       'data' => l(t('Cancel OpenID login'), '#'),
+       'class' => 'user-link',
+     );
+-    
++
+     $form['openid_links'] = array(
+       '#value' => theme('item_list', $items),
+       '#weight' => 1,
+@@ -215,12 +215,13 @@
+  *   $response['status'] set to one of 'success', 'failed' or 'cancel'.
+  */
+ function openid_complete($response = array()) {
++  global $base_url;
+   module_load_include('inc', 'openid');
+ 
+   if (count($response) == 0) {
+     $response = _openid_response();
+   }
+-  
++
+   // Default to failed response
+   $response['status'] = 'failed';
+   if (isset($_SESSION['openid']['service']['uri']) && isset($_SESSION['openid']['claimed_id'])) {
+@@ -233,7 +234,7 @@
+         $response['status'] = 'cancel';
+       }
+       else {
+-        if (openid_verify_assertion($service['uri'], $response)) {
++        if (openid_verify_assertion($service, $response)) {
+           // If the returned claimed_id is different from the session claimed_id,
+           // then we need to do discovery and make sure the op_endpoint matches.
+           if ($service['version'] == 2 && $response['openid.claimed_id'] != $claimed_id) {
+@@ -245,6 +246,31 @@
+           else {
+             $response['openid.claimed_id'] = $claimed_id;
+           }
++          // Verify that openid.return_to matches the current URL (see OpenID
++          // Authentication 2.0, section 11.1).
++          // While OpenID Authentication 1.1, section 4.3 does not mandate
++          // return_to verification, the received return_to should still
++          // match these constraints.
++          $return_to_parts = parse_url($response['openid.return_to']);
++
++          $base_url_parts = parse_url($base_url);
++          $current_parts = parse_url($base_url_parts['scheme'] .'://'. $base_url_parts['host'] . request_uri());
++
++          if ($return_to_parts['scheme'] != $current_parts['scheme'] ||
++              $return_to_parts['host'] != $current_parts['host'] ||
++              $return_to_parts['path'] != $current_parts['path']) {
++
++            return $response;
++          }
++          // Verify that all query parameters in the openid.return_to URL have
++          // the same value in the current URL. In addition, the current URL
++          // contains a number of other parameters added by the OpenID Provider.
++          parse_str(isset($return_to_parts['query']) ? $return_to_parts['query'] : '', $return_to_query_parameters);
++          foreach ($return_to_query_parameters as $name => $value) {
++            if (!array_key_exists($name, $_GET) || $_GET[$name] != $value) {
++              return $response;
++            }
++          }
+           $response['status'] = 'success';
+         }
+       }
+@@ -487,33 +513,39 @@
+ /**
+  * Attempt to verify the response received from the OpenID Provider.
+  *
+- * @param $op_endpoint The OpenID Provider URL.
+- * @param $response Array of repsonse values from the provider.
++ * @param $service
++ *   Array describing the OpenID provider.
++ * @param $response
++ *   Array of response values from the provider.
+  *
+  * @return boolean
+  */
+-function openid_verify_assertion($op_endpoint, $response) {
++function openid_verify_assertion($service, $response) {
+   module_load_include('inc', 'openid');
+ 
+-  $valid = FALSE;
++  // http://openid.net/specs/openid-authentication-2_0.html#rfc.section.11.3
++  // Check the Nonce to protect against replay attacks.
++  if (!openid_verify_assertion_nonce($service, $response)) {
++    return FALSE;
++  }
+ 
++  // http://openid.net/specs/openid-authentication-2_0.html#rfc.section.11.4
++  // Verify the signatures.
++  $valid = FALSE;
+   $association = db_fetch_object(db_query("SELECT * FROM {openid_association} WHERE assoc_handle = '%s'", $response['openid.assoc_handle']));
+   if ($association && isset($association->session_type)) {
+-    $keys_to_sign = explode(',', $response['openid.signed']);
+-    $self_sig = _openid_signature($association, $response, $keys_to_sign);
+-    if ($self_sig == $response['openid.sig']) {
+-      $valid = TRUE;
+-    }
+-    else {
+-      $valid = FALSE;
+-    }
++    // http://openid.net/specs/openid-authentication-2_0.html#rfc.section.11.4.2
++    // Verification using an association.
++    $valid = openid_verify_assertion_signature($service, $association, $response);
+   }
+   else {
++    // http://openid.net/specs/openid-authentication-2_0.html#rfc.section.11.4.3
++    // Direct verification.
+     $request = $response;
+     $request['openid.mode'] = 'check_authentication';
+     $message = _openid_create_message($request);
+     $headers = array('Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8');
+-    $result = drupal_http_request($op_endpoint, $headers, 'POST', _openid_encode_message($message));
++    $result = drupal_http_request($service['uri'], $headers, 'POST', _openid_encode_message($message));
+     if (!isset($result->error)) {
+       $response = _openid_parse_message($result->data);
+       if (strtolower(trim($response['is_valid'])) == 'true') {
+@@ -529,3 +561,101 @@
+   }
+   return $valid;
+ }
++
++/**
++ * Verify the signature of the response received from the OpenID provider.
++ *
++ * @param $service
++ *   Array describing the OpenID provider.
++ * @param $association
++ *   Information on the association with the OpenID provider.
++ * @param $response
++ *   Array of response values from the provider.
++ *
++ * @return
++ *   TRUE if the signature is valid and covers all fields required to be signed.
++ * @see http://openid.net/specs/openid-authentication-2_0.html#rfc.section.11.4
++ */
++function openid_verify_assertion_signature($service, $association, $response) {
++  if ($service['version'] == 2) {
++    // OpenID Authentication 2.0, section 10.1:
++    // These keys must always be signed.
++    $mandatory_keys = array('op_endpoint', 'return_to', 'response_nonce', 'assoc_handle');
++    if (isset($response['openid.claimed_id'])) {
++      // If present, these two keys must also be signed. According to the spec,
++      // they are either both present or both absent.
++      $mandatory_keys[] = 'claimed_id';
++      $mandatory_keys[] = 'identity';
++    }
++  }
++  else {
++    // OpenID Authentication 1.1. section 4.3.3.
++    $mandatory_keys = array('identity', 'return_to');
++  }
++
++  $keys_to_sign = explode(',', $response['openid.signed']);
++
++  if (count(array_diff($mandatory_keys, $keys_to_sign)) > 0) {
++    return FALSE;
++  }
++
++  return _openid_signature($association, $response, $keys_to_sign) == $response['openid.sig'];
++}
++
++/**
++ * Verify that the nonce has not been used in earlier assertions from the same OpenID provider.
++ *
++ * @param $service
++ *   Array describing the OpenID provider.
++ * @param $response
++ *   Array of response values from the provider.
++ *
++ * @return
++ *   TRUE if the nonce has not expired and has not been used earlier.
++ */
++function openid_verify_assertion_nonce($service, $response) {
++  if ($service['version'] != 2) {
++    return TRUE;
++  }
++
++  if (preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z/', $response['openid.response_nonce'], $matches)) {
++    list(, $year, $month, $day, $hour, $minutes, $seconds) = $matches;
++    $nonce_timestamp = gmmktime($hour, $minutes, $seconds, $month, $day, $year);
++  }
++  else {
++    watchdog('openid', 'Nonce from @endpoint rejected because it is not correctly formatted, nonce: @nonce.', array('@endpoint' => $service['uri'], '@nonce' => $response['openid.response_nonce']), WATCHDOG_WARNING);
++    return FALSE;
++  }
++
++  // A nonce with a timestamp to far in the past or future will already have
++  // been removed and cannot be checked for single use anymore.
++  $time = time();
++  $expiry = 900;
++  if ($nonce_timestamp <= $time - $expiry || $nonce_timestamp >= $time + $expiry) {
++    watchdog('openid', 'Nonce received from @endpoint is out of range (time difference: @intervals). Check possible clock skew.', array('@endpoint' => $service['uri'], '@interval' => $time - $nonce_timestamp), WATCHDOG_WARNING);
++    return FALSE;
++  }
++
++  // Record that this nonce was used.
++  db_query("INSERT INTO {openid_nonce} (idp_endpoint_uri, nonce, expires) VALUES ('%s', '%s', %d)", $service['uri'], $response['openid.response_nonce'], $nonce_timestamp + $expiry);
++
++  // Count the number of times this nonce was used.
++  $count_used = db_result(db_query("SELECT COUNT(*) FROM {openid_nonce} WHERE nonce = '%s' AND idp_endpoint_uri = '%s'", $response['openid.response_nonce'], $service['uri']));
++
++  if ($count_used == 1) {
++    return TRUE;
++  }
++  else {
++    watchdog('openid', 'Nonce replay attempt blocked from @ip, nonce: @nonce.', array('@ip' => ip_address(), '@nonce' => $response['openid.response_nonce']), WATCHDOG_CRITICAL);
++    return FALSE;
++  }
++}
++
++/**
++ * Remove expired nonces from the database.
++ *
++ * Implementation of hook_cron().
++ */
++function openid_cron() {
++  db_query("DELETE FROM {openid_nonce} WHERE expires < %d", time());
++}
+diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' lenny~/modules/system/system.module lenny/modules/system/system.module
+--- lenny~/modules/system/system.module	2009-08-05 02:51:12.000000000 +0200
++++ lenny/modules/system/system.module	2010-09-09 08:35:16.000000000 +0200
+@@ -1338,7 +1338,7 @@
+   while ($action = db_fetch_object($result)) {
+     $row[] = array(
+       array('data' => $action->type),
+-      array('data' => $action->description),
++      array('data' => filter_xss_admin($action->description)),
+       array('data' => $action->parameters ? l(t('configure'), "admin/settings/actions/configure/$action->aid") : ''),
+       array('data' => $action->parameters ? l(t('delete'), "admin/settings/actions/delete/$action->aid") : '')
+     );
+@@ -1544,9 +1544,8 @@
+   $aid = $form_state['values']['aid'];
+   $action = actions_load($aid);
+   actions_delete($aid);
+-  $description = check_plain($action->description);
+-  watchdog('user', 'Deleted action %aid (%action)', array('%aid' => $aid, '%action' => $description));
+-  drupal_set_message(t('Action %action was deleted', array('%action' => $description)));
++  watchdog('user', 'Deleted action %aid (%action)', array('%aid' => $aid, '%action' => $action->description));
++  drupal_set_message(t('Action %action was deleted', array('%action' => $action->description)));
+   $form_state['redirect'] = 'admin/settings/actions/manage';
+ }
+ 
+@@ -1746,7 +1745,7 @@
+     );
+   }
+   $subject = strtr($context['subject'], $variables);
+-  $body = strtr($context['message'], $variables);
++  $body = strtr(filter_xss_admin($context['message']), $variables);
+   $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
+   $message['body'][] = drupal_html_to_text($body);
+ }
+@@ -1795,11 +1794,11 @@
+     case 'taxonomy':
+       $vocabulary = taxonomy_vocabulary_load($object->vid);
+       $variables = array_merge($variables, array(
+-        '%term_name' => $object->name,
+-        '%term_description' => $object->description,
++        '%term_name' => check_plain($object->name),
++        '%term_description' => filter_xss_admin($object->description),
+         '%term_id' => $object->tid,
+-        '%vocabulary_name' => $vocabulary->name,
+-        '%vocabulary_description' => $vocabulary->description,
++        '%vocabulary_name' => check_plain($vocabulary->name),
++        '%vocabulary_description' => filter_xss_admin($vocabulary->description),
+         '%vocabulary_id' => $vocabulary->vid,
+         )
+       );
+@@ -1814,13 +1813,13 @@
+       '%uid' => $node->uid,
+       '%node_url' => url('node/'. $node->nid, array('absolute' => TRUE)),
+       '%node_type' => check_plain(node_get_types('name', $node)),
+-      '%title' => filter_xss($node->title),
+-      '%teaser' => filter_xss($node->teaser),
+-      '%body' => filter_xss($node->body),
++      '%title' => check_plain($node->title),
++      '%teaser' => check_markup($node->teaser, $node->format, FALSE),
++      '%body' => check_markup($node->body, $node->format, FALSE),
+       )
+     );
+   }
+-  $context['message'] = strtr($context['message'], $variables);
++  $context['message'] = strtr(filter_xss_admin($context['message']), $variables);
+   drupal_set_message($context['message']);
+ }
+ 
+diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' lenny~/modules/trigger/trigger.admin.inc lenny/modules/trigger/trigger.admin.inc
+--- lenny~/modules/trigger/trigger.admin.inc	2009-08-05 02:52:02.000000000 +0200
++++ lenny/modules/trigger/trigger.admin.inc	2010-09-09 08:35:16.000000000 +0200
+@@ -1,5 +1,5 @@
+ <?php
+-// $Id: trigger.admin.inc,v 1.5 2008/01/08 10:35:43 goba Exp $
++// $Id: trigger.admin.inc,v 1.5.4.1 2010/08/11 20:22:27 goba Exp $
+ 
+ /**
+  * @file
+@@ -84,7 +84,7 @@
+     $aid = actions_function_lookup($form_values['aid']);
+     db_query("DELETE FROM {trigger_assignments} WHERE hook = '%s' AND op = '%s' AND aid = '%s'", $form_values['hook'], $form_values['operation'], $aid);
+     $actions = actions_get_all_actions();
+-    watchdog('actions', 'Action %action has been unassigned.',  array('%action' => check_plain($actions[$aid]['description'])));
++    watchdog('actions', 'Action %action has been unassigned.',  array('%action' => $actions[$aid]['description']));
+     drupal_set_message(t('Action %action has been unassigned.', array('%action' => $actions[$aid]['description'])));
+     $hook = $form_values['hook'] == 'nodeapi' ? 'node' : $form_values['hook'];
+     $form_state['redirect'] = 'admin/build/trigger/'. $hook;
+@@ -239,7 +239,7 @@
+     $rows = array();
+     foreach ($element['assigned']['#value'] as $aid => $info) {
+       $rows[] = array(
+-        $info['description'],
++        filter_xss_admin($info['description']),
+         $info['link']
+       );
+     }
+diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' lenny~/modules/upload/upload.module lenny/modules/upload/upload.module
+--- lenny~/modules/upload/upload.module	2009-08-05 02:51:14.000000000 +0200
++++ lenny/modules/upload/upload.module	2010-09-09 08:35:16.000000000 +0200
+@@ -147,7 +147,13 @@
+ function upload_file_download($filepath) {
+   $filepath = file_create_path($filepath);
+   $result = db_query("SELECT f.*, u.nid FROM {files} f INNER JOIN {upload} u ON f.fid = u.fid WHERE filepath = '%s'", $filepath);
+-  if ($file = db_fetch_object($result)) {
++  while ($file = db_fetch_object($result)) {
++    if ($filepath !== $file->filepath) {
++      // Since some database servers sometimes use a case-insensitive
++      // comparison by default, double check that the filename is an exact
++      // match.
++      continue;
++    }
+     if (user_access('view uploaded files') && ($node = node_load($file->nid)) && node_access('view', $node)) {
+       return array(
+         'Content-Type: ' . $file->filemime,

Propchange: branches/lenny-security/debian/patches/20_SA-CORE-2010-002.dpatch
------------------------------------------------------------------------------
    svn:executable = *




More information about the Pkg-drupal-commits mailing list