Skip to content

phar extension heap use after free #23418

Description

@devnexen

Description

The following code:

<?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

$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

PHP 8.6.0-dev

Operating System

/

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions