summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorxjm2019-01-15 17:41:52 (GMT)
committerxjm2019-01-15 17:41:52 (GMT)
commit5ed2a9f0ab5ce8280aebd18f9ee8c3d80cfd3c63 (patch)
tree4617c239bed2ed406d885e264b926dbbdbd9a1fc /core
parent1a8e6de9de0b12cc13d4020ea290327b86a8ba12 (diff)
SA-CORE-2019-001 by Ayesh, alexpott, larowlan, xjm, michieltcs, farisv
Diffstat (limited to 'core')
-rw-r--r--core/lib/Drupal/Core/Archiver/ArchiveTar.php191
1 files changed, 124 insertions, 67 deletions
diff --git a/core/lib/Drupal/Core/Archiver/ArchiveTar.php b/core/lib/Drupal/Core/Archiver/ArchiveTar.php
index 716511e..abee870 100644
--- a/core/lib/Drupal/Core/Archiver/ArchiveTar.php
+++ b/core/lib/Drupal/Core/Archiver/ArchiveTar.php
@@ -42,7 +42,7 @@
/**
* Note on Drupal 8 porting.
- * This file origin is Tar.php, release 1.4.0 (stable) with some code
+ * This file origin is Tar.php, release 1.4.5 (stable) with some code
* from PEAR.php, release 1.9.5 (stable) both at http://pear.php.net.
* To simplify future porting from pear of this file, you should not
* do cosmetic or other non significant changes to this file.
@@ -152,6 +152,13 @@ class ArchiveTar
public $error_object = null;
/**
+ * Format for data extraction
+ *
+ * @var string
+ */
+ public $_fmt ='';
+
+ /**
* Archive_Tar Class constructor. This flavour of the constructor only
* declare a new Archive_Tar object, identifying it by the name of the
* tar file.
@@ -257,6 +264,18 @@ class ArchiveTar
return false;
}
}
+
+ if (version_compare(PHP_VERSION, "5.5.0-dev") < 0) {
+ $this->_fmt = "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
+ "a8checksum/a1typeflag/a100link/a6magic/a2version/" .
+ "a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
+ } else {
+ $this->_fmt = "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/" .
+ "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
+ "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
+ }
+
+
}
public function __destruct()
@@ -712,7 +731,7 @@ class ArchiveTar
}
// ----- Get the arguments
- $v_att_list = & func_get_args();
+ $v_att_list = func_get_args();
// ----- Read the attributes
$i = 0;
@@ -1392,10 +1411,20 @@ class ArchiveTar
if ($p_stored_filename == '') {
$p_stored_filename = $p_filename;
}
- $v_reduce_filename = $this->_pathReduction($p_stored_filename);
+ $v_reduced_filename = $this->_pathReduction($p_stored_filename);
- if (strlen($v_reduce_filename) > 99) {
- if (!$this->_writeLongHeader($v_reduce_filename)) {
+ if (strlen($v_reduced_filename) > 99) {
+ if (!$this->_writeLongHeader($v_reduced_filename, false)) {
+ return false;
+ }
+ }
+
+ $v_linkname = '';
+ if (@is_link($p_filename)) {
+ $v_linkname = readlink($p_filename);
+ }
+ if (strlen($v_linkname) > 99) {
+ if (!$this->_writeLongHeader($v_linkname, true)) {
return false;
}
}
@@ -1404,14 +1433,10 @@ class ArchiveTar
$v_uid = sprintf("%07s", DecOct($v_info[4]));
$v_gid = sprintf("%07s", DecOct($v_info[5]));
$v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777));
-
$v_mtime = sprintf("%011s", DecOct($v_info['mtime']));
- $v_linkname = '';
-
if (@is_link($p_filename)) {
$v_typeflag = '2';
- $v_linkname = readlink($p_filename);
$v_size = sprintf("%011s", DecOct(0));
} elseif (@is_dir($p_filename)) {
$v_typeflag = "5";
@@ -1423,7 +1448,6 @@ class ArchiveTar
}
$v_magic = 'ustar ';
-
$v_version = ' ';
if (function_exists('posix_getpwuid')) {
@@ -1438,14 +1462,12 @@ class ArchiveTar
}
$v_devmajor = '';
-
$v_devminor = '';
$v_prefix = '';
$v_binary_data_first = pack(
"a100a8a8a8a12a12",
- $v_reduce_filename,
$v_perms,
$v_uid,
$v_gid,
@@ -1485,7 +1507,7 @@ class ArchiveTar
$this->_writeBlock($v_binary_data_first, 148);
// ----- Write the calculated checksum
- $v_checksum = sprintf("%06s ", DecOct($v_checksum));
+ $v_checksum = sprintf("%06s\0 ", DecOct($v_checksum));
$v_binary_data = pack("a8", $v_checksum);
$this->_writeBlock($v_binary_data, 8);
@@ -1517,7 +1539,7 @@ class ArchiveTar
$p_filename = $this->_pathReduction($p_filename);
if (strlen($p_filename) > 99) {
- if (!$this->_writeLongHeader($p_filename)) {
+ if (!$this->_writeLongHeader($p_filename, false)) {
return false;
}
}
@@ -1613,36 +1635,31 @@ class ArchiveTar
* @param string $p_filename
* @return bool
*/
- public function _writeLongHeader($p_filename)
+ public function _writeLongHeader($p_filename, $is_link = false)
{
- $v_size = sprintf("%11s ", DecOct(strlen($p_filename)));
-
- $v_typeflag = 'L';
-
+ $v_uid = sprintf("%07s", 0);
+ $v_gid = sprintf("%07s", 0);
+ $v_perms = sprintf("%07s", 0);
+ $v_size = sprintf("%'011s", DecOct(strlen($p_filename)));
+ $v_mtime = sprintf("%011s", 0);
+ $v_typeflag = ($is_link ? 'K' : 'L');
$v_linkname = '';
-
- $v_magic = '';
-
- $v_version = '';
-
+ $v_magic = 'ustar ';
+ $v_version = ' ';
$v_uname = '';
-
$v_gname = '';
-
$v_devmajor = '';
-
$v_devminor = '';
-
$v_prefix = '';
$v_binary_data_first = pack(
"a100a8a8a8a12a12",
'././@LongLink',
- 0,
- 0,
- 0,
+ $v_perms,
+ $v_uid,
+ $v_gid,
$v_size,
- 0
+ $v_mtime
);
$v_binary_data_last = pack(
"a1a100a6a2a32a32a8a8a155a12",
@@ -1677,7 +1694,7 @@ class ArchiveTar
$this->_writeBlock($v_binary_data_first, 148);
// ----- Write the calculated checksum
- $v_checksum = sprintf("%06s ", DecOct($v_checksum));
+ $v_checksum = sprintf("%06s\0 ", DecOct($v_checksum));
$v_binary_data = pack("a8", $v_checksum);
$this->_writeBlock($v_binary_data, 8);
@@ -1718,28 +1735,12 @@ class ArchiveTar
// ----- Calculate the checksum
$v_checksum = 0;
// ..... First part of the header
- for ($i = 0; $i < 148; $i++) {
- $v_checksum += ord(substr($v_binary_data, $i, 1));
- }
- // ..... Ignore the checksum value and replace it by ' ' (space)
- for ($i = 148; $i < 156; $i++) {
- $v_checksum += ord(' ');
- }
- // ..... Last part of the header
- for ($i = 156; $i < 512; $i++) {
- $v_checksum += ord(substr($v_binary_data, $i, 1));
- }
+ $v_binary_split = str_split($v_binary_data);
+ $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 0, 148)));
+ $v_checksum += array_sum(array_map('ord', array(' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',)));
+ $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 156, 512)));
- if (version_compare(PHP_VERSION, "5.5.0-dev") < 0) {
- $fmt = "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
- "a8checksum/a1typeflag/a100link/a6magic/a2version/" .
- "a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
- } else {
- $fmt = "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/" .
- "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
- "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
- }
- $v_data = unpack($fmt, $v_binary_data);
+ $v_data = unpack($this->_fmt, $v_binary_data);
if (strlen($v_data["prefix"]) > 0) {
$v_data["filename"] = "$v_data[prefix]/$v_data[filename]";
@@ -1775,7 +1776,7 @@ class ArchiveTar
$v_header['mode'] = OctDec(trim($v_data['mode']));
$v_header['uid'] = OctDec(trim($v_data['uid']));
$v_header['gid'] = OctDec(trim($v_data['gid']));
- $v_header['size'] = OctDec(trim($v_data['size']));
+ $v_header['size'] = $this->_tarRecToSize($v_data['size']);
$v_header['mtime'] = OctDec(trim($v_data['mtime']));
if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
$v_header['size'] = 0;
@@ -1795,6 +1796,41 @@ class ArchiveTar
}
/**
+ * Convert Tar record size to actual size
+ *
+ * @param string $tar_size
+ * @return size of tar record in bytes
+ */
+ private function _tarRecToSize($tar_size)
+ {
+ /*
+ * First byte of size has a special meaning if bit 7 is set.
+ *
+ * Bit 7 indicates base-256 encoding if set.
+ * Bit 6 is the sign bit.
+ * Bits 5:0 are most significant value bits.
+ */
+ $ch = ord($tar_size[0]);
+ if ($ch & 0x80) {
+ // Full 12-bytes record is required.
+ $rec_str = $tar_size . "\x00";
+
+ $size = ($ch & 0x40) ? -1 : 0;
+ $size = ($size << 6) | ($ch & 0x3f);
+
+ for ($num_ch = 1; $num_ch < 12; ++$num_ch) {
+ $size = ($size * 256) + ord($rec_str[$num_ch]);
+ }
+
+ return $size;
+
+ } else {
+ return OctDec(trim($tar_size));
+ }
+ }
+
+
+ /**
* Detect and report a malicious file name
*
* @param string $file
@@ -1803,10 +1839,13 @@ class ArchiveTar
*/
private function _maliciousFilename($file)
{
- if (strpos($file, '/../') !== false) {
+ if (strpos($file, 'phar://') === 0) {
return true;
}
- if (strpos($file, '../') === 0) {
+ if (strpos($file, DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR) !== false) {
+ return true;
+ }
+ if (strpos($file, '..' . DIRECTORY_SEPARATOR) === 0) {
return true;
}
return false;
@@ -1871,11 +1910,20 @@ class ArchiveTar
continue;
}
- // ----- Look for long filename
- if ($v_header['typeflag'] == 'L') {
- if (!$this->_readLongHeader($v_header)) {
- return null;
- }
+ switch ($v_header['typeflag']) {
+ case 'L': {
+ if (!$this->_readLongHeader($v_header)) {
+ return null;
+ }
+ } break;
+
+ case 'K': {
+ $v_link_header = $v_header;
+ if (!$this->_readLongHeader($v_link_header)) {
+ return null;
+ }
+ $v_header['link'] = $v_link_header['filename'];
+ } break;
}
if ($v_header['filename'] == $p_filename) {
@@ -1976,11 +2024,20 @@ class ArchiveTar
continue;
}
- // ----- Look for long filename
- if ($v_header['typeflag'] == 'L') {
- if (!$this->_readLongHeader($v_header)) {
- return false;
- }
+ switch ($v_header['typeflag']) {
+ case 'L': {
+ if (!$this->_readLongHeader($v_header)) {
+ return null;
+ }
+ } break;
+
+ case 'K': {
+ $v_link_header = $v_header;
+ if (!$this->_readLongHeader($v_link_header)) {
+ return null;
+ }
+ $v_header['link'] = $v_link_header['filename'];
+ } break;
}
// ignore extended / pax headers