Skip to content

Invalid read/segfault on specific input #177

@michael-grunder

Description

@michael-grunder

Hi again 👋,

I found a flaw in msgpack on a specific input string.

Very easy to reproducer:

<?php
$data = hex2bin('de06000000c09baa316e3b303e66656367675203060657545563343864643600000000');
$unserilized = msgpack_unserialize($data);

With the zend allocator:

 valgrind sapi/cli/php unserialize.php
==3142543== Memcheck, a memory error detector
==3142543== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==3142543== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==3142543== Command: sapi/cli/php unserialize.php
==3142543==
==3142543== Warning: set address range perms: large range [0x59c95000, 0xd9c95000) (defined)
==3142543== Warning: set address range perms: large range [0x59c96000, 0xd9c95000) (undefined)

Warning: [msgpack] (php_msgpack_unserialize) Insufficient data for unserializing in /home/mike/dev/phpfarm/src/php-8.3.11-debug/unserialize.php on line 4
php: /home/mike/dev/phpfarm/src/php-8.3.11-debug/Zend/zend_gc.c:698: gc_possible_root: Assertion `zval_gc_type((ref)->gc.u.type_info) == 7 || zval_gc_type((ref)->gc.u.type_info) == 8' failed.
==3142543==
==3142543== Process terminating with default action of signal 6 (SIGABRT)
==3142543==    at 0x5E009FC: __pthread_kill_implementation (pthread_kill.c:44)
==3142543==    by 0x5E009FC: __pthread_kill_internal (pthread_kill.c:78)
==3142543==    by 0x5E009FC: pthread_kill@@GLIBC_2.34 (pthread_kill.c:89)
==3142543==    by 0x5DAC475: raise (raise.c:26)
==3142543==    by 0x5D927F2: abort (abort.c:79)
==3142543==    by 0x5D9271A: __assert_fail_base.cold (assert.c:92)
==3142543==    by 0x5DA3E95: __assert_fail (assert.c:101)
==3142543==    by 0xEA5570: gc_possible_root (zend_gc.c:698)
==3142543==    by 0xDD50CA: gc_check_possible_root (zend_gc.h:98)
==3142543==    by 0xDD511C: i_zval_ptr_dtor (zend_variables.h:46)
==3142543==    by 0xDD52EB: zval_ptr_dtor (zend_variables.c:84)
==3142543==    by 0x8C9D3B: msgpack_unserialize_var_destroy (msgpack_unpack.c:364)
==3142543==    by 0x8C4DB9: php_msgpack_unserialize (msgpack.c:279)
==3142543==    by 0x8C4F2D: zif_msgpack_unserialize (msgpack.c:318)
==3142543==
==3142543== HEAP SUMMARY:
==3142543==     in use at exit: 3,418,965 bytes in 27,735 blocks
==3142543==   total heap usage: 30,680 allocs, 2,944 frees, 2,151,772,892 bytes allocated
==3142543==
==3142543== LEAK SUMMARY:
==3142543==    definitely lost: 34,983 bytes in 986 blocks
==3142543==    indirectly lost: 40 bytes in 1 blocks
==3142543==      possibly lost: 2,619,303 bytes in 21,628 blocks
==3142543==    still reachable: 2,148,244,191 bytes in 5,121 blocks
==3142543==         suppressed: 0 bytes in 0 blocks
==3142543== Rerun with --leak-check=full to see details of leaked memory
==3142543==
==3142543== For lists of detected and suppressed errors, rerun with: -s
==3142543== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
[1]    3142543 IOT instruction (core dumped)  valgrind sapi/cli/php unserialize.php

Without the allocator:

 USE_ZEND_ALLOC=0 valgrind sapi/cli/php unserialize.php
==3142751== Memcheck, a memory error detector
==3142751== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==3142751== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==3142751== Command: sapi/cli/php unserialize.php
==3142751==
==3142751== Warning: set address range perms: large range [0x59c95000, 0xd9c95000) (defined)
==3142751== Warning: set address range perms: large range [0x59c96000, 0xd9c95000) (undefined)

Warning: [msgpack] (php_msgpack_unserialize) Insufficient data for unserializing in /home/mike/dev/phpfarm/src/php-8.3.11-debug/unserialize.php on line 4
==3142751== Invalid read of size 4
==3142751==    at 0xDD4E45: zend_gc_delref (zend_types.h:1342)
==3142751==    by 0xDD50FE: i_zval_ptr_dtor (zend_variables.h:43)
==3142751==    by 0xDD52EB: zval_ptr_dtor (zend_variables.c:84)
==3142751==    by 0x8C9D3B: msgpack_unserialize_var_destroy (msgpack_unpack.c:364)
==3142751==    by 0x8C4DB9: php_msgpack_unserialize (msgpack.c:279)
==3142751==    by 0x8C4F2D: zif_msgpack_unserialize (msgpack.c:318)
==3142751==    by 0xE18658: ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER (zend_vm_execute.h:1337)
==3142751==    by 0xE8E113: execute_ex (zend_vm_execute.h:57216)
==3142751==    by 0xE92959: zend_execute (zend_vm_execute.h:61604)
==3142751==    by 0xDD9AAA: zend_execute_scripts (zend.c:1891)
==3142751==    by 0xD37F82: php_execute_script (main.c:2528)
==3142751==    by 0xF4C25A: do_cli (php_cli.c:966)
==3142751==  Address 0xa07ee50 is 0 bytes inside a block of size 56 free'd
==3142751==    at 0x484C9F4: free (vg_replace_malloc.c:989)
==3142751==    by 0xD9AF5D: _efree_custom (zend_alloc.c:2500)
==3142751==    by 0xD9B0A8: _efree (zend_alloc.c:2620)
==3142751==    by 0xDF2F95: zend_array_destroy (zend_hash.c:1867)
==3142751==    by 0xDD517A: rc_dtor_func (zend_variables.c:57)
==3142751==    by 0xDD510E: i_zval_ptr_dtor (zend_variables.h:44)
==3142751==    by 0xDD52EB: zval_ptr_dtor (zend_variables.c:84)
==3142751==    by 0x8CADD3: msgpack_unserialize_map_item (msgpack_unpack.c:647)
==3142751==    by 0x8C4511: msgpack_unserialize_execute (unpack_template.h:405)
==3142751==    by 0x8C4B9D: php_msgpack_unserialize (msgpack.c:252)
==3142751==    by 0x8C4F2D: zif_msgpack_unserialize (msgpack.c:318)
==3142751==    by 0xE18658: ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER (zend_vm_execute.h:1337)
==3142751==  Block was alloc'd at
==3142751==    at 0x484977B: malloc (vg_replace_malloc.c:446)
==3142751==    by 0xD9C29B: __zend_malloc (zend_alloc.c:3128)
==3142751==    by 0xD9AEF0: _malloc_custom (zend_alloc.c:2491)
==3142751==    by 0xD9B02E: _emalloc (zend_alloc.c:2610)
==3142751==    by 0xDEDEC9: _zend_new_array (zend_hash.c:291)
==3142751==    by 0x8CA788: msgpack_unserialize_array (msgpack_unpack.c:550)
==3142751==    by 0x8C39BA: msgpack_unserialize_execute (unpack_template.h:231)
==3142751==    by 0x8C4B9D: php_msgpack_unserialize (msgpack.c:252)
==3142751==    by 0x8C4F2D: zif_msgpack_unserialize (msgpack.c:318)
==3142751==    by 0xE18658: ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER (zend_vm_execute.h:1337)
==3142751==    by 0xE8E113: execute_ex (zend_vm_execute.h:57216)
==3142751==    by 0xE92959: zend_execute (zend_vm_execute.h:61604)
==3142751==
php: /home/mike/dev/phpfarm/src/php-8.3.11-debug/Zend/zend_types.h:1342: zend_gc_delref: Assertion `p->refcount > 0' failed.
==3142751==
==3142751== Process terminating with default action of signal 6 (SIGABRT)
==3142751==    at 0x5E009FC: __pthread_kill_implementation (pthread_kill.c:44)
==3142751==    by 0x5E009FC: __pthread_kill_internal (pthread_kill.c:78)
==3142751==    by 0x5E009FC: pthread_kill@@GLIBC_2.34 (pthread_kill.c:89)
==3142751==    by 0x5DAC475: raise (raise.c:26)
==3142751==    by 0x5D927F2: abort (abort.c:79)
==3142751==    by 0x5D9271A: __assert_fail_base.cold (assert.c:92)
==3142751==    by 0x5DA3E95: __assert_fail (assert.c:101)
==3142751==    by 0xDD4E63: zend_gc_delref (zend_types.h:1342)
==3142751==    by 0xDD50FE: i_zval_ptr_dtor (zend_variables.h:43)
==3142751==    by 0xDD52EB: zval_ptr_dtor (zend_variables.c:84)
==3142751==    by 0x8C9D3B: msgpack_unserialize_var_destroy (msgpack_unpack.c:364)
==3142751==    by 0x8C4DB9: php_msgpack_unserialize (msgpack.c:279)
==3142751==    by 0x8C4F2D: zif_msgpack_unserialize (msgpack.c:318)
==3142751==    by 0xE18658: ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER (zend_vm_execute.h:1337)
==3142751==
==3142751== HEAP SUMMARY:
==3142751==     in use at exit: 3,854,817 bytes in 27,959 blocks
==3142751==   total heap usage: 31,192 allocs, 3,232 frees, 2,152,369,935 bytes allocated
==3142751==
==3142751== LEAK SUMMARY:
==3142751==    definitely lost: 34,983 bytes in 986 blocks
==3142751==    indirectly lost: 40 bytes in 1 blocks
==3142751==      possibly lost: 2,679,753 bytes in 21,820 blocks
==3142751==    still reachable: 2,148,619,593 bytes in 5,153 blocks
==3142751==         suppressed: 0 bytes in 0 blocks
==3142751== Rerun with --leak-check=full to see details of leaked memory
==3142751==
==3142751== For lists of detected and suppressed errors, rerun with: -s
==3142751== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
[1]    3142751 IOT instruction (core dumped)  USE_ZEND_ALLOC=0 valgrind sapi/cli/php unserialize.php

I can replicate the problem both in debug and release builds of PHP. I'm using 8.3.11 here though.

PHP 8.3.11 (cli) (built: Aug 30 2024 09:27:49) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.11, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.11, Copyright (c), by Zend Technologies

Let me know if I can provide any other info.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions