Skip to content

Commit 1045989

Browse files
authored
Improve path handling in extractor (#6290)
1 parent 6869dac commit 1045989

File tree

1 file changed

+19
-49
lines changed

1 file changed

+19
-49
lines changed

php/WP_CLI/Extractor.php

Lines changed: 19 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,15 @@ private static function extract_tarball( $tarball, $dest ) {
121121
}
122122
}
123123

124-
// Ensure relative paths cannot be misinterpreted as hostnames.
125-
// Prepending `./` will force tar to interpret it as a filesystem path.
126-
if ( self::path_is_relative( $tarball ) ) {
127-
$tarball = "./{$tarball}";
124+
$tarball_absolute = realpath( $tarball );
125+
if ( ! $tarball_absolute ) {
126+
throw new Exception( "Invalid tarball '{$tarball}'." );
128127
}
128+
$tarball = $tarball_absolute;
129129

130-
if ( ! file_exists( $tarball )
131-
|| ! is_readable( $tarball )
130+
if ( ! is_readable( $tarball )
132131
|| filesize( $tarball ) <= 0 ) {
133-
throw new Exception( "Invalid zip file '{$tarball}'." );
132+
throw new Exception( "Invalid tarball '{$tarball}'." );
134133
}
135134

136135
// Note: directory must exist for tar --directory to work.
@@ -220,17 +219,27 @@ public static function rmdir( $dir ) {
220219
RecursiveIteratorIterator::CHILD_FIRST
221220
);
222221

222+
$base_dir = realpath( $dir );
223+
if ( false === $base_dir ) {
224+
return;
225+
}
226+
$base_dir = rtrim( $base_dir, DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR;
227+
223228
/**
224229
* @var \SplFileInfo $fileinfo
225230
*/
226231
foreach ( $files as $fileinfo ) {
227-
$todo = $fileinfo->isDir() ? 'rmdir' : 'unlink';
228-
$path = $fileinfo->getRealPath();
229-
if ( 0 !== strpos( $path, $fileinfo->getRealPath() ) ) {
232+
$todo = $fileinfo->isDir() ? 'rmdir' : 'unlink';
233+
$path = $fileinfo->getPathname();
234+
$real_path = $fileinfo->getRealPath();
235+
236+
if ( ! $real_path || 0 !== strpos( $real_path, $base_dir ) ) {
230237
WP_CLI::warning(
231238
"Temporary file or folder to be removed was found outside of temporary folder, aborting removal: '{$path}'"
232239
);
240+
continue;
233241
}
242+
234243
$todo( $path );
235244
}
236245
rmdir( $dir );
@@ -345,43 +354,4 @@ private static function ensure_dir_exists( $dir ) {
345354

346355
return true;
347356
}
348-
349-
/**
350-
* Check whether a path is relative-
351-
*
352-
* @param string $path Path to check.
353-
* @return bool Whether the path is relative.
354-
*/
355-
private static function path_is_relative( $path ) {
356-
if ( '' === $path ) {
357-
return true;
358-
}
359-
360-
// Strip scheme.
361-
$scheme_position = strpos( $path, '://' );
362-
if ( false !== $scheme_position ) {
363-
$path = substr( $path, $scheme_position + 3 );
364-
}
365-
366-
// UNIX root "/" or "\" (Windows style).
367-
if ( '/' === $path[0] || '\\' === $path[0] ) {
368-
return false;
369-
}
370-
371-
// Windows root.
372-
if ( strlen( $path ) > 1 && ctype_alpha( $path[0] ) && ':' === $path[1] ) {
373-
374-
// Special case: only drive letter, like "C:".
375-
if ( 2 === strlen( $path ) ) {
376-
return false;
377-
}
378-
379-
// Regular Windows path starting with drive letter, like "C:/ or "C:\".
380-
if ( '/' === $path[2] || '\\' === $path[2] ) {
381-
return false;
382-
}
383-
}
384-
385-
return true;
386-
}
387357
}

0 commit comments

Comments
 (0)