[php-src] Issue #23418: phar extension heap use after free

[email protected] (devnexen)
Newsgroups php.bugs
Message-ID <mO9qu5ZDhT7ZCEDb6mHRjLmufJ4nXgE1WRp4eEMG5kc@main.internal.php.net>
Issue: https://github.com/php/php-src/issues/23418
Author: devnexen

### Description

The following code:

```php
<?php
$phar = __DIR__ . '/base.phar';
@unlink($phar);
$p = new Phar($phar);
$p->addFromString('x.txt', 'x');
$p->setStub('<?php __HALT_COMPILER(); ?>');
unset($p);

@mkdir(__DIR__ . '/mnt/s2', 0777, true);

$p = new Phar($phar);
Phar::mount('phar://' . $phar . '/m', __DIR__ . '/mnt');
$p['m/s2/'];
```

Resulted in this output:
```
==ERROR: AddressSanitizer: heap-use-after-free on address 0x...
READ of size 3 at 0x... thread T0
    #0 strlen
    #1 xbuf_format_converter                  main/spprintf.c:526
    #2 php_printf_to_smart_string              main/spprintf.c:767
    #3 zend_vspprintf                          Zend/zend.c:298
    #4 zend_spprintf                           Zend/zend.c:322
    #5 phar_get_entry_info_dir                 ext/phar/util.c:1322   <-- use
    #6 zim_Phar_offsetGet                      ext/phar/phar_object.c:3522
    #7 zend_call_function ...
   #12 zend_std_read_dimension                 Zend/zend_object_handlers.c:1388
   #15 ZEND_FETCH_DIM_R_SPEC_CV_CONST_HANDLER  ($p['m/s2/'])

0x... is located 0 bytes inside of 224-byte region
freed by thread T0 here:
    #2 _efree                                  Zend/zend_alloc.c:2788
    #3 phar_get_entry_info_dir                 ext/phar/util.c:1320
    #4 zim_Phar_offsetGet                      ext/phar/phar_object.c:3522

previously allocated by thread T0 here:
    #3 _smart_string_alloc                     Zend/zend_smart_str.c:170
    #9 zend_spprintf                           Zend/zend.c:322
   #10 phar_get_entry_info_dir                 ext/phar/util.c:1294
```

But I expected this output instead:
```
PharFileInfo, isDir=true
```

while at it, I stumbled across a memory leak with the following 

```php
$stub = "<?php __HALT_COMPILER(); ?>\r\n";

function u32($v) { return pack('V', $v); }

function ent($name, $data, $meta = '') {
    $h = u32(strlen($name)) . $name
       . u32(strlen($data)) . u32(0) . u32(strlen($data))
       . u32(crc32($data)) . u32(0)
       . u32(strlen($meta)) . $meta;
    return [$h, $data];
}

$e1 = ent('a.txt', 'hello', 'i:1;');
$e2 = ent('a.txt', 'world', 'i:2;');

$ents = $e1[0] . $e2[0];
$contents = $e1[1] . $e2[1];

$manifest = u32(2) . "\x11\x00" . u32(0) . u32(0) . u32(0) . $ents;

file_put_contents(__DIR__ . '/dup.phar', $stub . u32(strlen($manifest)) . $manifest . $contents);

$p = new Phar(__DIR__ . '/dup.phar');
echo iterator_count($p), PHP_EOL;
```

```
==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 32 byte(s) in 1 object(s) allocated from:
    #4 zend_string_init                        Zend/zend_string.h:212
    #5 phar_parse_metadata_lazy                ext/phar/phar.c:705
    #6 phar_parse_pharfile                     ext/phar/phar.c:1191
    #10 zim_Phar___construct                   ext/phar/phar_object.c:1125

Direct leak of 32 byte(s) in 1 object(s) allocated from:
    #4 zend_string_init                        Zend/zend_string.h:212
    #5 phar_parse_pharfile                     ext/phar/phar.c:1177
    #9 zim_Phar___construct                    ext/phar/phar_object.c:1125
```


### PHP Version

```plain
PHP 8.6.0-dev
```

### Operating System

/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.