Make WordPress Core

Changeset 42011


Ignore:
Timestamp:
10/24/2017 11:14:33 PM (7 years ago)
Author:
johnbillion
Message:

Filesystem API: Add more specificity to the rules for valid files in validate_file().

This now treats files containing ./ as valid, and also treats files containing a trailing ../ as valid due to widespread use of this pattern in theme and plugin zip files.

Adds tests.

Props Ipstenu, borgesbruno, DavidAnderson, philipjohn, birgire
Fixes #42016, #36170

Location:
trunk
Files:
3 edited

Legend:

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

    r42010 r42011  
    664664 * @return string|null
    665665 */
    666 function validate_file_to_edit( $file, $allowed_files = '' ) {
     666function validate_file_to_edit( $file, $allowed_files = array() ) {
    667667    $code = validate_file( $file, $allowed_files );
    668668
  • trunk/src/wp-includes/functions.php

    r42007 r42011  
    42534253 * @return int 0 means nothing is wrong, greater than 0 means something was wrong.
    42544254 */
    4255 function validate_file( $file, $allowed_files = '' ) {
    4256     if ( false !== strpos( $file, '..' ) )
     4255function validate_file( $file, $allowed_files = array() ) {
     4256    // `../` on its own is not allowed:
     4257    if ( '../' === $file ) {
    42574258        return 1;
    4258 
    4259     if ( false !== strpos( $file, './' ) )
     4259    }
     4260
     4261    // More than one occurence of `../` is not allowed:
     4262    if ( preg_match_all( '#\.\./#', $file, $matches, PREG_SET_ORDER ) && ( count( $matches ) > 1 ) ) {
    42604263        return 1;
    4261 
     4264    }
     4265
     4266    // `../` which does not occur at the end of the path is not allowed:
     4267    if ( false !== strpos( $file, '../' ) && '../' !== mb_substr( $file, -3, 3 ) ) {
     4268        return 1;
     4269    }
     4270
     4271    // Files not in the allowed file list are not allowed:
    42624272    if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files ) )
    42634273        return 3;
    42644274
     4275    // Absolute Windows drive paths are not allowed:
    42654276    if (':' == substr( $file, 1, 1 ) )
    42664277        return 2;
  • trunk/tests/phpunit/tests/functions.php

    r41623 r42011  
    11621162    }
    11631163
     1164    /**
     1165     * Test file path validation
     1166     *
     1167     * @ticket 42016
     1168     * @dataProvider data_test_validate_file()
     1169     *
     1170     * @param string $file          File path.
     1171     * @param array  $allowed_files List of allowed files.
     1172     * @param int    $expected      Expected result.
     1173     */
     1174    public function test_validate_file( $file, $allowed_files, $expected ) {
     1175        $this->assertSame( $expected, validate_file( $file, $allowed_files ) );
     1176    }
     1177
     1178    /**
     1179     * Data provider for file validation.
     1180     *
     1181     * @return array {
     1182     *     @type array $0... {
     1183     *         @type string $0 File path.
     1184     *         @type array  $1 List of allowed files.
     1185     *         @type int    $2 Expected result.
     1186     *     }
     1187     * }
     1188     */
     1189    public function data_test_validate_file() {
     1190        return array(
     1191
     1192            // Allowed files:
     1193            array(
     1194                null,
     1195                array(),
     1196                0,
     1197            ),
     1198            array(
     1199                '',
     1200                array(),
     1201                0,
     1202            ),
     1203            array(
     1204                ' ',
     1205                array(),
     1206                0,
     1207            ),
     1208            array(
     1209                '.',
     1210                array(),
     1211                0,
     1212            ),
     1213            array(
     1214                '..',
     1215                array(),
     1216                0,
     1217            ),
     1218            array(
     1219                './',
     1220                array(),
     1221                0,
     1222            ),
     1223            array(
     1224                'foo.ext',
     1225                array( 'foo.ext' ),
     1226                0,
     1227            ),
     1228            array(
     1229                'dir/foo.ext',
     1230                array(),
     1231                0,
     1232            ),
     1233            array(
     1234                'foo..ext',
     1235                array(),
     1236                0,
     1237            ),
     1238            array(
     1239                'dir/dir/../',
     1240                array(),
     1241                0,
     1242            ),
     1243
     1244            // Directory traversal:
     1245            array(
     1246                '../',
     1247                array(),
     1248                1,
     1249            ),
     1250            array(
     1251                '../../',
     1252                array(),
     1253                1,
     1254            ),
     1255            array(
     1256                '../file.ext',
     1257                array(),
     1258                1,
     1259            ),
     1260            array(
     1261                '../dir/../',
     1262                array(),
     1263                1,
     1264            ),
     1265            array(
     1266                '/dir/dir/../../',
     1267                array(),
     1268                1,
     1269            ),
     1270            array(
     1271                '/dir/dir/../../',
     1272                array( '/dir/dir/../../' ),
     1273                1,
     1274            ),
     1275
     1276            // Windows drives:
     1277            array(
     1278                'c:',
     1279                array(),
     1280                2,
     1281            ),
     1282            array(
     1283                'C:/WINDOWS/system32',
     1284                array( 'C:/WINDOWS/system32' ),
     1285                2,
     1286            ),
     1287
     1288            // Disallowed files:
     1289            array(
     1290                'foo.ext',
     1291                array( 'bar.ext' ),
     1292                3,
     1293            ),
     1294            array(
     1295                'foo.ext',
     1296                array( '.ext' ),
     1297                3,
     1298            ),
     1299            array(
     1300                'path/foo.ext',
     1301                array( 'foo.ext' ),
     1302                3,
     1303            ),
     1304
     1305        );
     1306    }
    11641307}
Note: See TracChangeset for help on using the changeset viewer.