Make WordPress Core

Changeset 51910


Ignore:
Timestamp:
10/15/2021 10:23:35 PM (2 years ago)
Author:
hellofromTonya
Message:

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.
  1. 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.

  1. 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.

Location:
trunk
Files:
1 added
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/functions.php

    r51885 r51910  
    82228222 *
    82238223 * @since 5.6.0
     8224 * @since 5.9.0 Added input validation with a notice for invalid input.
    82248225 *
    82258226 * @param string $path Full path of a directory or file.
    82268227 */
    82278228function clean_dirsize_cache( $path ) {
     8229    if ( ! is_string( $path ) || empty( $path ) ) {
     8230        trigger_error(
     8231            sprintf(
     8232                /* translators: 1: Function name, 2: A variable type, like "boolean" or "integer". */
     8233                __( '%1$s only accepts a non-empty path string, received %2$s.' ),
     8234                '<code>clean_dirsize_cache()</code>',
     8235                '<code>' . gettype( $path ) . '</code>'
     8236            )
     8237        );
     8238        return;
     8239    }
     8240
    82288241    $directory_cache = get_transient( 'dirsize_cache' );
    82298242
     
    82328245    }
    82338246
    8234     $path = untrailingslashit( $path );
     8247    if (
     8248        strpos( $path, '/' ) === false &&
     8249        strpos( $path, '\\' ) === false
     8250    ) {
     8251        unset( $directory_cache[ $path ] );
     8252        set_transient( 'dirsize_cache', $directory_cache );
     8253        return;
     8254    }
     8255
     8256    $last_path = null;
     8257    $path      = untrailingslashit( $path );
    82358258    unset( $directory_cache[ $path ] );
    82368259
    8237     while ( DIRECTORY_SEPARATOR !== $path && '.' !== $path && '..' !== $path ) {
    8238         $path = dirname( $path );
     8260    while (
     8261        $last_path !== $path &&
     8262        DIRECTORY_SEPARATOR !== $path &&
     8263        '.' !== $path &&
     8264        '..' !== $path
     8265    ) {
     8266        $last_path = $path;
     8267        $path      = dirname( $path );
    82398268        unset( $directory_cache[ $path ] );
    82408269    }
Note: See TracChangeset for help on using the changeset viewer.