diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 8c651312f5e9c06bebf6785c62bdba1e2a142aaa..8a567dc0623eabf0584fa9fb59328358591d2d14 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,6 +1,11 @@ Drupal 7.xx, xxxx-xx-xx (development version) ----------------------- +Drupal 7.65, 2019-03-20 +----------------------- +- Fixed security issues: + - SA-CORE-2019-004 + Drupal 7.64, 2019-02-06 ----------------------- - [regression] Unset the 'host' header in drupal_http_request() during redirect diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index db2ac1f5d123e344c406b304b7ddaa36e9806cfc..1b5c53408f8a356036bdafd6f0eaf527594dc6ff 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -8,7 +8,7 @@ /** * The current system version. */ -define('VERSION', '7.64'); +define('VERSION', '7.65'); /** * Core API compatibility. diff --git a/includes/file.inc b/includes/file.inc index d6f315602ecf1241512450f775e63259e13ce2fd..8943d63a029a117e050906a89a12c5cc2bde1c67 100644 --- a/includes/file.inc +++ b/includes/file.inc @@ -997,8 +997,15 @@ function file_build_uri($path) { * @return * The destination filepath, or FALSE if the file already exists * and FILE_EXISTS_ERROR is specified. + * + * @throws RuntimeException + * Thrown if the filename contains invalid UTF-8. */ function file_destination($destination, $replace) { + $basename = drupal_basename($destination); + if (!drupal_validate_utf8($basename)) { + throw new RuntimeException(sprintf("Invalid filename '%s'", $basename)); + } if (file_exists($destination)) { switch ($replace) { case FILE_EXISTS_REPLACE: @@ -1006,7 +1013,6 @@ function file_destination($destination, $replace) { break; case FILE_EXISTS_RENAME: - $basename = drupal_basename($destination); $directory = drupal_dirname($destination); $destination = file_create_filename($basename, $directory); break; @@ -1222,11 +1228,20 @@ function file_unmunge_filename($filename) { * @return * File path consisting of $directory and a unique filename based off * of $basename. + * + * @throws RuntimeException + * Thrown if the $basename is not valid UTF-8 or another error occurs + * stripping control characters. */ function file_create_filename($basename, $directory) { + $original = $basename; // Strip control characters (ASCII value < 32). Though these are allowed in // some filesystems, not many applications handle them well. $basename = preg_replace('/[\x00-\x1F]/u', '_', $basename); + if (preg_last_error() !== PREG_NO_ERROR) { + throw new RuntimeException(sprintf("Invalid filename '%s'", $original)); + } + if (substr(PHP_OS, 0, 3) == 'WIN') { // These characters are not allowed in Windows filenames $basename = str_replace(array(':', '*', '?', '"', '<', '>', '|'), '_', $basename); @@ -1567,7 +1582,13 @@ function file_save_upload($form_field_name, $validators = array(), $destination if (substr($destination, -1) != '/') { $destination .= '/'; } - $file->destination = file_destination($destination . $file->filename, $replace); + try { + $file->destination = file_destination($destination . $file->filename, $replace); + } + catch (RuntimeException $e) { + drupal_set_message(t('The file %source could not be uploaded because the name is invalid.', array('%source' => $form_field_name)), 'error'); + return FALSE; + } // If file_destination() returns FALSE then $replace == FILE_EXISTS_ERROR and // there's an existing file so we need to bail. if ($file->destination === FALSE) { diff --git a/modules/simpletest/tests/file.test b/modules/simpletest/tests/file.test index 55dd1906ee89c8ac377ba02321d5bad57e65e2cc..032f2cbac58c3772a31e291ecf72fed1926f33a2 100644 --- a/modules/simpletest/tests/file.test +++ b/modules/simpletest/tests/file.test @@ -957,6 +957,15 @@ class FileDirectoryTest extends FileTestCase { $path = file_create_filename($basename, $directory); $this->assertEqual($path, $expected, format_string('Creating a new filepath from %original equals %new.', array('%new' => $path, '%original' => $original)), 'File'); + try { + $filename = "a\xFFtest\x80€.txt"; + file_create_filename($filename, $directory); + $this->fail('Expected exception not thrown'); + } + catch (RuntimeException $e) { + $this->assertEqual("Invalid filename '$filename'", $e->getMessage()); + } + // @TODO: Finally we copy a file into a directory several times, to ensure a properly iterating filename suffix. } @@ -989,6 +998,14 @@ class FileDirectoryTest extends FileTestCase { $this->assertNotEqual($path, $destination, 'A new filepath destination is created when filepath destination already exists with FILE_EXISTS_RENAME.', 'File'); $path = file_destination($destination, FILE_EXISTS_ERROR); $this->assertEqual($path, FALSE, 'An error is returned when filepath destination already exists with FILE_EXISTS_ERROR.', 'File'); + + try { + file_destination("core/misc/a\xFFtest\x80€.txt", FILE_EXISTS_REPLACE); + $this->fail('Expected exception not thrown'); + } + catch (RuntimeException $e) { + $this->assertEqual("Invalid filename 'a\xFFtest\x80€.txt'", $e->getMessage()); + } } /** diff --git a/profiles/wcm_base/CHANGELOG.txt b/profiles/wcm_base/CHANGELOG.txt index 95a733ad8caa245b7cc0d98b5a6a7625d00301b1..5f210c5f587e3948f0bf6e42adc1a2ba16653761 100644 --- a/profiles/wcm_base/CHANGELOG.txt +++ b/profiles/wcm_base/CHANGELOG.txt @@ -1,3 +1,7 @@ +WCM Base 7.x-1.13-rc2, 2019-03-20 +--------------------------------- +- WCM Base: Updated Drupal core to 7.65 per SA-CORE-2019-004. + WCM Base 7.x-1.13-rc1, 2019-03-13 --------------------------------- - WCM Base: