Version in base suite: 6.6-3lenny2 Version in overlay suite: (not present) Base version: drupal6_6.6-3lenny2 Target version: drupal6_6.6-3lenny3 Base file: /org/ftp.debian.org/ftp/pool/main/d/drupal6/drupal6_6.6-3lenny2.dsc Target file: /org/ftp.debian.org/queue/p-u-new/drupal6_6.6-3lenny3.dsc debian/patches/16_SA-CORE-2009-007.dpatch | 222 ++++++++++++++++++++++++++++++ debian/patches/17_SA-CORE-2009-008.dpatch | 79 ++++++++++ drupal6-6.6/debian/changelog | 13 + drupal6-6.6/debian/patches/00list | 2 4 files changed, 316 insertions(+) diff -u drupal6-6.6/debian/changelog drupal6-6.6/debian/changelog --- drupal6-6.6/debian/changelog +++ drupal6-6.6/debian/changelog @@ -1,3 +1,16 @@ +drupal6 (6.6-3lenny3) stable-security; urgency=low + + [ Luigi Gangitano ] + * debian/patches/16_SA-CORE-2009-007 + - Fix cross-site scripting (XSS) issues (Closes: #535435, #535476) + (Ref: SA-CORE-2009-007, CVE-2009-2372, CVE-2009-2373, CVE-2009-2374) + + * debian/patches/17_SA-CORE-2009-008 + - Fix XSS, OpenID impersonation and Session Fixation issues (Closes: #547140) + (Ref: SA-CORE-2009-008, CVE-TBD) + + -- Luigi Gangitano Fri, 06 Nov 2009 00:16:01 +0100 + drupal6 (6.6-3lenny2) stable-security; urgency=high * Non-maintainer upload by the security team diff -u drupal6-6.6/debian/patches/00list drupal6-6.6/debian/patches/00list --- drupal6-6.6/debian/patches/00list +++ drupal6-6.6/debian/patches/00list @@ -5,0 +6,2 @@ +16_SA-CORE-2009-007 +17_SA-CORE-2009-008 only in patch2: unchanged: --- drupal6-6.6.orig/debian/patches/16_SA-CORE-2009-007.dpatch +++ drupal6-6.6/debian/patches/16_SA-CORE-2009-007.dpatch @@ -0,0 +1,222 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 16_SA-CORE-2009-007.dpatch by Luigi Gangitano +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +@DPATCH@ +diff -urNad lenny~/includes/pager.inc lenny/includes/pager.inc +--- lenny~/includes/pager.inc 2009-08-05 02:51:00.000000000 +0200 ++++ lenny/includes/pager.inc 2009-11-06 00:21:34.000000000 +0100 +@@ -85,7 +85,7 @@ + function pager_get_querystring() { + static $string = NULL; + if (!isset($string)) { +- $string = drupal_query_string_encode($_REQUEST, array_merge(array('q', 'page'), array_keys($_COOKIE))); ++ $string = drupal_query_string_encode($_REQUEST, array_merge(array('q', 'page', 'pass'), array_keys($_COOKIE))); + } + return $string; + } +diff -urNad lenny~/includes/tablesort.inc lenny/includes/tablesort.inc +--- lenny~/includes/tablesort.inc 2009-08-05 02:51:00.000000000 +0200 ++++ lenny/includes/tablesort.inc 2009-11-06 00:21:34.000000000 +0100 +@@ -136,7 +136,7 @@ + * except for those pertaining to table sorting. + */ + function tablesort_get_querystring() { +- return drupal_query_string_encode($_REQUEST, array_merge(array('q', 'sort', 'order'), array_keys($_COOKIE))); ++ return drupal_query_string_encode($_REQUEST, array_merge(array('q', 'sort', 'order', 'pass'), array_keys($_COOKIE))); + } + + /** +diff -urNad lenny~/modules/comment/comment.module lenny/modules/comment/comment.module +--- lenny~/modules/comment/comment.module 2009-08-05 02:52:00.000000000 +0200 ++++ lenny/modules/comment/comment.module 2009-11-06 00:21:34.000000000 +0100 +@@ -936,7 +936,7 @@ + + if ($cid && is_numeric($cid)) { + // Single comment view. +- $query = 'SELECT c.cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name, c.mail, c.homepage, u.uid, u.name AS registered_name, u.signature, u.picture, u.data, c.status FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d'; ++ $query = 'SELECT c.cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name, c.mail, c.homepage, u.uid, u.name AS registered_name, u.signature, u.signature_format, u.picture, u.data, c.status FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d'; + $query_args = array($cid); + if (!user_access('administer comments')) { + $query .= ' AND c.status = %d'; +@@ -957,7 +957,7 @@ + else { + // Multiple comment view + $query_count = 'SELECT COUNT(*) FROM {comments} c WHERE c.nid = %d'; +- $query = 'SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name, c.mail, c.homepage, u.uid, u.name AS registered_name, u.signature, u.picture, u.data, c.thread, c.status FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = %d'; ++ $query = 'SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name, c.mail, c.homepage, u.uid, u.name AS registered_name, u.signature, u.signature_format, u.picture, u.data, c.thread, c.status FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = %d'; + + $query_args = array($nid); + if (!user_access('administer comments')) { +@@ -1466,7 +1466,7 @@ + $output = ''; + + if ($edit['pid']) { +- $comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.signature, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = %d', $edit['pid'], COMMENT_PUBLISHED)); ++ $comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.signature, u.signature_format, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = %d', $edit['pid'], COMMENT_PUBLISHED)); + $comment = drupal_unpack($comment); + $comment->name = $comment->uid ? $comment->registered_name : $comment->name; + $output .= theme('comment_view', $comment, $node); +@@ -1774,14 +1774,14 @@ + function theme_comment_post_forbidden($node) { + global $user; + static $authenticated_post_comments; +- ++ + if (!$user->uid) { + if (!isset($authenticated_post_comments)) { + // We only output any link if we are certain, that users get permission + // to post comments by logging in. We also locally cache this information. + $authenticated_post_comments = array_key_exists(DRUPAL_AUTHENTICATED_RID, user_roles(TRUE, 'post comments') + user_roles(TRUE, 'post comments without approval')); + } +- ++ + if ($authenticated_post_comments) { + // We cannot use drupal_get_destination() because these links + // sometimes appear on /node and taxonomy listing pages. +diff -urNad lenny~/modules/comment/comment.pages.inc lenny/modules/comment/comment.pages.inc +--- lenny~/modules/comment/comment.pages.inc 2009-08-05 02:52:00.000000000 +0200 ++++ lenny/modules/comment/comment.pages.inc 2009-11-06 00:21:34.000000000 +0100 +@@ -70,7 +70,7 @@ + // $pid indicates that this is a reply to a comment. + if ($pid) { + // load the comment whose cid = $pid +- if ($comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.signature, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = %d', $pid, COMMENT_PUBLISHED))) { ++ if ($comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.signature, u.signature_format, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = %d', $pid, COMMENT_PUBLISHED))) { + // If that comment exists, make sure that the current comment and the parent comment both + // belong to the same parent node. + if ($comment->nid != $node->nid) { +diff -urNad lenny~/modules/forum/forum.pages.inc lenny/modules/forum/forum.pages.inc +--- lenny~/modules/forum/forum.pages.inc 2009-08-05 02:51:46.000000000 +0200 ++++ lenny/modules/forum/forum.pages.inc 2009-11-06 00:21:34.000000000 +0100 +@@ -10,6 +10,11 @@ + * Menu callback; prints a forum listing. + */ + function forum_page($tid = 0) { ++ if (!is_numeric($tid)) { ++ return MENU_NOT_FOUND; ++ } ++ $tid = (int)$tid; ++ + $topics = ''; + $forum_per_page = variable_get('forum_per_page', 25); + $sortby = variable_get('forum_order', 1); +diff -urNad lenny~/modules/system/system.install lenny/modules/system/system.install +--- lenny~/modules/system/system.install 2009-08-05 02:51:12.000000000 +0200 ++++ lenny/modules/system/system.install 2009-11-06 00:25:42.000000000 +0100 +@@ -2518,8 +2518,58 @@ + return $ret; + } + ++/** ++ * Replace src index on the {url_alias} table with src, language. ++ */ ++function system_update_6049() { ++ $ret = array(); ++ db_drop_index($ret, 'url_alias', 'src'); ++ db_add_index($ret, 'url_alias', 'src_language', array('src', 'language')); ++ return $ret;} + + /** +- * @} End of "defgroup updates-5.x-to-6.x" ++ * Clear any menu router blobs stored in the cache table. ++ */ ++function system_update_6050() { ++ $ret = array(); ++ cache_clear_all('router:', 'cache_menu', TRUE); ++ return $ret; ++} ++ ++/** ++ * Create a signature_format column. ++ */ ++function system_update_6051() { ++ $ret = array(); ++ ++ if (!db_column_exists('users', 'signature_format')) { ++ ++ // Set future input formats to FILTER_FORMAT_DEFAULT to ensure a safe default ++ // when incompatible modules insert into the users table. An actual format ++ // will be assigned when users save their signature. ++ ++ $schema = array( ++ 'type' => 'int', ++ 'size' => 'small', ++ 'not null' => TRUE, ++ 'default' => FILTER_FORMAT_DEFAULT, ++ 'description' => 'The {filter_formats}.format of the signature.', ++ ); ++ ++ db_add_field($ret, 'users', 'signature_format', $schema); ++ ++ // Set the format of existing signatures to the current default input format. ++ if ($current_default_filter = variable_get('filter_default_format', 0)) { ++ $ret[] = update_sql("UPDATE {users} SET signature_format = ". $current_default_filter); ++ } ++ ++ drupal_set_message("User signatures no longer inherit comment input formats. Each user's signature now has its own associated format that can be selected on the user's account page. Existing signatures have been set to your site's default input format."); ++ } ++ ++ return $ret; ++} ++ ++/** ++ * @} End of "defgroup updates-6.x-extra" + * The next series of updates should start at 7000. + */ +diff -urNad lenny~/modules/user/user.install lenny/modules/user/user.install +--- lenny~/modules/user/user.install 2009-08-05 02:52:10.000000000 +0200 ++++ lenny/modules/user/user.install 2009-11-06 00:21:34.000000000 +0100 +@@ -191,6 +191,13 @@ + 'default' => '', + 'description' => t("User's signature."), + ), ++ 'signature_format' => array( ++ 'type' => 'int', ++ 'size' => 'small', ++ 'not null' => TRUE, ++ 'default' => 0, ++ 'description' => 'The {filter_formats}.format of the signature.', ++ ), + 'created' => array( + 'type' => 'int', + 'not null' => TRUE, +diff -urNad lenny~/modules/user/user.module lenny/modules/user/user.module +--- lenny~/modules/user/user.module 2009-11-06 00:21:12.000000000 +0100 ++++ lenny/modules/user/user.module 2009-11-06 00:21:34.000000000 +0100 +@@ -530,7 +530,7 @@ + } + else { + // Make sure we return the default fields at least. +- $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'access', 'login', 'status', 'timezone', 'language', 'init', 'data'); ++ $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'signature_format', 'created', 'access', 'login', 'status', 'timezone', 'language', 'init', 'data'); + } + } + +@@ -1518,6 +1518,15 @@ + '#default_value' => $edit['signature'], + '#description' => t('Your signature will be publicly displayed at the end of your comments.'), + ); ++ ++ // Prevent a "validation error" message when the user attempts to save with a default value they ++ // do not have access to. ++ if (!filter_access($edit['signature_format']) && empty($_POST)) { ++ drupal_set_message(t("The signature input format has been set to a format you don't have access to. It will be changed to a format you have access to when you save this page.")); ++ $edit['signature_format'] = FILTER_FORMAT_DEFAULT; ++ } ++ ++ $form['signature_settings']['signature_format'] = filter_form($edit['signature_format'], NULL, array('signature_format')); + } + + // Picture/avatar: +@@ -2031,7 +2040,7 @@ + // Validate signature. + if ($op == 'view') { + if (variable_get('user_signatures', 0) && !empty($comment->signature)) { +- $comment->signature = check_markup($comment->signature, $comment->format); ++ $comment->signature = check_markup($comment->signature, $comment->signature_format, FALSE); + } + else { + $comment->signature = ''; only in patch2: unchanged: --- drupal6-6.6.orig/debian/patches/17_SA-CORE-2009-008.dpatch +++ drupal6-6.6/debian/patches/17_SA-CORE-2009-008.dpatch @@ -0,0 +1,79 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 17_SA-CORE-2009-008.dpatch by Luigi Gangitano +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +@DPATCH@ +diff -urNad lenny~/includes/file.inc lenny/includes/file.inc +--- lenny~/includes/file.inc 2009-08-05 02:50:57.000000000 +0200 ++++ lenny/includes/file.inc 2009-11-06 00:33:34.000000000 +0100 +@@ -529,13 +529,6 @@ + $file->filepath = $_FILES['files']['tmp_name'][$source]; + $file->filemime = file_get_mimetype($file->filename); + +- // Rename potentially executable files, to help prevent exploits. +- if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) { +- $file->filemime = 'text/plain'; +- $file->filepath .= '.txt'; +- $file->filename .= '.txt'; +- } +- + // If the destination is not provided, or is not writable, then use the + // temporary directory. + if (empty($dest) || file_check_path($dest) === FALSE) { +@@ -553,6 +546,18 @@ + $errors = array_merge($errors, call_user_func_array($function, $args)); + } + ++ // Rename potentially executable files, to help prevent exploits. ++ if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) { ++ $file->filemime = 'text/plain'; ++ $file->filepath .= '.txt'; ++ $file->filename .= '.txt'; ++ // As the file may be named example.php.txt, we need to munge again to ++ // convert to example.php_.txt, then create the correct destination. ++ $file->filename = file_munge_filename($file->filename, $extensions); ++ $file->destination = file_destination(file_create_path($dest .'/'. $file->filename), $replace); ++ } ++ ++ + // Check for validation errors. + if (!empty($errors)) { + $message = t('The selected file %name could not be uploaded.', array('%name' => $file->filename)); +diff -urNad lenny~/modules/openid/openid.module lenny/modules/openid/openid.module +--- lenny~/modules/openid/openid.module 2009-08-05 02:51:31.000000000 +0200 ++++ lenny/modules/openid/openid.module 2009-11-06 00:33:34.000000000 +0100 +@@ -193,8 +193,8 @@ + } + + if (isset($services[0]['types']) && is_array($services[0]['types']) && in_array(OPENID_NS_2_0 .'/server', $services[0]['types'])) { +- $identity = 'http://specs.openid.net/auth/2.0/identifier_select'; +- } ++ $claimed_id = $identity = 'http://specs.openid.net/auth/2.0/identifier_select'; ++ } + $authn_request = openid_authentication_request($claimed_id, $identity, $return_to, $assoc_handle, $services[0]['version']); + + if ($services[0]['version'] == 2) { +diff -urNad lenny~/modules/openid/openid.pages.inc lenny/modules/openid/openid.pages.inc +--- lenny~/modules/openid/openid.pages.inc 2009-08-05 02:51:31.000000000 +0200 ++++ lenny/modules/openid/openid.pages.inc 2009-11-06 00:33:34.000000000 +0100 +@@ -73,12 +73,14 @@ + if (db_result(db_query("SELECT authname FROM {authmap} WHERE authname='%s'", $claimed_id))) { + form_set_error('openid_identifier', t('That OpenID is already in use on this site.')); + } +- else { +- $return_to = url('user/'. arg(1) .'/openid', array('absolute' => TRUE)); +- openid_begin($form_state['values']['openid_identifier'], $return_to); +- } + } + ++function openid_user_add_submit($form, &$form_state) { ++ $return_to = url('user/'. arg(1) .'/openid', array('absolute' => TRUE)); ++ openid_begin($form_state['values']['openid_identifier'], $return_to); ++} ++ ++ + /** + * Present a confirmation form to delete the specified OpenID identity from the system. + *