From 82141be0d85b7600fd19878a6f19929fed17a382 Mon Sep 17 00:00:00 2001 From: hellofromTonya Date: Fri, 15 Oct 2021 22:25:01 +0000 Subject: [PATCH] FileSystem API: Fix infinite loop on Windows for `clean_dirsize_cache()`. When the PHP native `dirname()` function is used on a Windows disk name - i.e. `C:\`-, it will return the same, i.e, it will return `C:\` again. The `clean_dirsize_cache()` function didn't have guard clause against this, which meant that on Windows based systems and IIS servers, this function would result in WordPress getting stuck into an infinite loop. The adjustment to the `while` part of the function fix this by checking if the return value of the `dirname()` function call is the same as the original path passed to `dirname()`, which effectively fixes the infinite loop. A number of other improvements made: 1. Add input validation for the `$path` parameter to guard against invalid variable types being passed into the function. 2. Guard against an empty `$path` parameter, which would result in an infinite loop on both Windows as well as *nix based systems. In both these cases, a PHP notice will now be thrown. 3. When a non-empty string, which isn't a path would previously be passed, the `dirname()` function would transform that to a `.` and the `.` key in the transient cache would be cleared out. This was a bug as there is no relation between a non-path string and the root directory of file system. This bug has been fixed by checking that something could actually be a path and handling received non-empty, non-path input parameters in a special way, i.e only removing the cache key for the passed string and bowing out from further processing. Unfortunately, no tests can be added to guard against the infinite loop. For the other fixes, we have added appropriate unit tests. Follow-up up [49212], [49616], [49744]. Props jrf, hellofromTonya, raubvogel, sergeybiryukov, codezen8, sjlevy, drosmog, teachlynx, ekojr, bartoszgrzesik, joegasper, janthiel, josephdickson, ocean90, audrasjb. Fixes #52241. Built from https://develop.svn.wordpress.org/trunk@51910 git-svn-id: http://core.svn.wordpress.org/trunk@51503 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/functions.php | 35 ++++++++++++++++++++++++++++++++--- wp-includes/version.php | 2 +- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/wp-includes/functions.php b/wp-includes/functions.php index aa507bb004..81409e9382 100644 --- a/wp-includes/functions.php +++ b/wp-includes/functions.php @@ -8221,21 +8221,50 @@ function recurse_dirsize( $directory, $exclude = null, $max_execution_time = nul * Removes the current directory and all parent directories from the `dirsize_cache` transient. * * @since 5.6.0 + * @since 5.9.0 Added input validation with a notice for invalid input. * * @param string $path Full path of a directory or file. */ function clean_dirsize_cache( $path ) { + if ( ! is_string( $path ) || empty( $path ) ) { + trigger_error( + sprintf( + /* translators: 1: Function name, 2: A variable type, like "boolean" or "integer". */ + __( '%1$s only accepts a non-empty path string, received %2$s.' ), + 'clean_dirsize_cache()', + '' . gettype( $path ) . '' + ) + ); + return; + } + $directory_cache = get_transient( 'dirsize_cache' ); if ( empty( $directory_cache ) ) { return; } - $path = untrailingslashit( $path ); + if ( + strpos( $path, '/' ) === false && + strpos( $path, '\\' ) === false + ) { + unset( $directory_cache[ $path ] ); + set_transient( 'dirsize_cache', $directory_cache ); + return; + } + + $last_path = null; + $path = untrailingslashit( $path ); unset( $directory_cache[ $path ] ); - while ( DIRECTORY_SEPARATOR !== $path && '.' !== $path && '..' !== $path ) { - $path = dirname( $path ); + while ( + $last_path !== $path && + DIRECTORY_SEPARATOR !== $path && + '.' !== $path && + '..' !== $path + ) { + $last_path = $path; + $path = dirname( $path ); unset( $directory_cache[ $path ] ); } diff --git a/wp-includes/version.php b/wp-includes/version.php index f1d2290c16..a21a3f77b4 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '5.9-alpha-51909'; +$wp_version = '5.9-alpha-51910'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.