Skip to content

UAF when unsetting ArrayObject element #16646

Closed

Description

@chibinz

Description

The following code:

<?php

class B {
    public $b;
    function __construct($arg) {
        $this->b = $arg;
    }
}

class C {
    function __destruct() {
        global $arr;
        $arr->exchangeArray([]);
    }
}

$arr = new ArrayObject(new B(new C));
unset($arr["b"]);

Resulted in this output:

==1989454==ERROR: AddressSanitizer: heap-use-after-free on address 0x6040000462d0 at pc 0x55e8c835f779 bp 0x7ffca005a370 sp 0x7ffca005a368
READ of size 4 at 0x6040000462d0 thread T0
    #0 0x55e8c835f778 in zend_gc_delref /tmp/php-asan/Zend/zend_types.h:1346:2
    #1 0x55e8c83608ab in zend_objects_store_del /tmp/php-asan/Zend/zend_objects_API.c:180:4
    #2 0x55e8c83c75b6 in rc_dtor_func /tmp/php-asan/Zend/zend_variables.c:57:2
    #3 0x55e8c83c76a4 in i_zval_ptr_dtor /tmp/php-asan/Zend/zend_variables.h:45:4
    #4 0x55e8c83c75f4 in zval_ptr_dtor /tmp/php-asan/Zend/zend_variables.c:84:2
    #5 0x55e8c77eb626 in spl_array_unset_dimension_ex /tmp/php-asan/ext/spl/spl_array.c:556:6
    #6 0x55e8c77f7f61 in spl_array_unset_dimension /tmp/php-asan/ext/spl/spl_array.c:580:2
    #7 0x55e8c80c847d in ZEND_UNSET_DIM_SPEC_CV_CONST_HANDLER /tmp/php-asan/Zend/zend_vm_execute.h:45268:4
    #8 0x55e8c7fb183d in execute_ex /tmp/php-asan/Zend/zend_vm_execute.h:58565:7
    #9 0x55e8c7fb2067 in zend_execute /tmp/php-asan/Zend/zend_vm_execute.h:64217:2
    #10 0x55e8c83e6860 in zend_execute_script /tmp/php-asan/Zend/zend.c:1932:3
    #11 0x55e8c7c04d2b in php_execute_script_ex /tmp/php-asan/main/main.c:2574:13
    #12 0x55e8c7c05228 in php_execute_script /tmp/php-asan/main/main.c:2614:9
    #13 0x55e8c83ee309 in do_cli /tmp/php-asan/sapi/cli/php_cli.c:935:5
    #14 0x55e8c83eb32c in main /tmp/php-asan/sapi/cli/php_cli.c:1310:18
    #15 0x7f7dd0c29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #16 0x7f7dd0c29e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #17 0x55e8c6e02de4 in _start (/workspaces/TriFuzz/targets/php-asan/bin/php+0x402de4)

0x6040000462d0 is located 0 bytes inside of 40-byte region [0x6040000462d0,0x6040000462f8)
freed by thread T0 here:
    #0 0x55e8c6e87702 in free /opt/llvm-15-build/llvm-15.x/final/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:52:3
    #1 0x55e8c7e418a3 in __zend_free /tmp/php-asan/Zend/zend_alloc.c:3308:2
    #2 0x55e8c7e45774 in _efree /tmp/php-asan/Zend/zend_alloc.c:2747:3
    #3 0x55e8c8360d5a in zend_objects_store_del /tmp/php-asan/Zend/zend_objects_API.c:198:3
    #4 0x55e8c8362ea6 in zend_object_release /tmp/php-asan/Zend/zend_objects_API.h:77:3
    #5 0x55e8c8362c7f in zend_objects_destroy_object /tmp/php-asan/Zend/zend_objects.c:204:3
    #6 0x55e8c83608a2 in zend_objects_store_del /tmp/php-asan/Zend/zend_objects_API.c:179:4
    #7 0x55e8c83c75b6 in rc_dtor_func /tmp/php-asan/Zend/zend_variables.c:57:2
    #8 0x55e8c83c76a4 in i_zval_ptr_dtor /tmp/php-asan/Zend/zend_variables.h:45:4
    #9 0x55e8c83c75f4 in zval_ptr_dtor /tmp/php-asan/Zend/zend_variables.c:84:2
    #10 0x55e8c77eb626 in spl_array_unset_dimension_ex /tmp/php-asan/ext/spl/spl_array.c:556:6
    #11 0x55e8c77f7f61 in spl_array_unset_dimension /tmp/php-asan/ext/spl/spl_array.c:580:2
    #12 0x55e8c80c847d in ZEND_UNSET_DIM_SPEC_CV_CONST_HANDLER /tmp/php-asan/Zend/zend_vm_execute.h:45268:4
    #13 0x55e8c7fb183d in execute_ex /tmp/php-asan/Zend/zend_vm_execute.h:58565:7
    #14 0x55e8c7fb2067 in zend_execute /tmp/php-asan/Zend/zend_vm_execute.h:64217:2
    #15 0x55e8c83e6860 in zend_execute_script /tmp/php-asan/Zend/zend.c:1932:3
    #16 0x55e8c7c04d2b in php_execute_script_ex /tmp/php-asan/main/main.c:2574:13
    #17 0x55e8c7c05228 in php_execute_script /tmp/php-asan/main/main.c:2614:9
    #18 0x55e8c83ee309 in do_cli /tmp/php-asan/sapi/cli/php_cli.c:935:5
    #19 0x55e8c83eb32c in main /tmp/php-asan/sapi/cli/php_cli.c:1310:18
    #20 0x7f7dd0c29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

previously allocated by thread T0 here:
    #0 0x55e8c6e879ae in malloc /opt/llvm-15-build/llvm-15.x/final/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:69:3
    #1 0x55e8c7e45ce3 in __zend_malloc /tmp/php-asan/Zend/zend_alloc.c:3280:14
    #2 0x55e8c7e45670 in _emalloc /tmp/php-asan/Zend/zend_alloc.c:2737:10
    #3 0x55e8c8362f63 in zend_objects_new /tmp/php-asan/Zend/zend_objects.c:210:24
    #4 0x55e8c7e5f92d in _object_and_properties_init /tmp/php-asan/Zend/zend_API.c:1823:22
    #5 0x55e8c7e5fb30 in object_init_ex /tmp/php-asan/Zend/zend_API.c:1846:9
    #6 0x55e8c80af338 in ZEND_NEW_SPEC_CONST_UNUSED_HANDLER /tmp/php-asan/Zend/zend_vm_execute.h:10923:6
    #7 0x55e8c7fb183d in execute_ex /tmp/php-asan/Zend/zend_vm_execute.h:58565:7
    #8 0x55e8c7fb2067 in zend_execute /tmp/php-asan/Zend/zend_vm_execute.h:64217:2
    #9 0x55e8c83e6860 in zend_execute_script /tmp/php-asan/Zend/zend.c:1932:3
    #10 0x55e8c7c04d2b in php_execute_script_ex /tmp/php-asan/main/main.c:2574:13
    #11 0x55e8c7c05228 in php_execute_script /tmp/php-asan/main/main.c:2614:9
    #12 0x55e8c83ee309 in do_cli /tmp/php-asan/sapi/cli/php_cli.c:935:5
    #13 0x55e8c83eb32c in main /tmp/php-asan/sapi/cli/php_cli.c:1310:18
    #14 0x7f7dd0c29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

SUMMARY: AddressSanitizer: heap-use-after-free /tmp/php-asan/Zend/zend_types.h:1346:2 in zend_gc_delref
Shadow bytes around the buggy address:
  0x0c0880000c00: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 00
  0x0c0880000c10: fa fa 00 00 00 00 00 fa fa fa fd fd fd fd fd fd
  0x0c0880000c20: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 fa
  0x0c0880000c30: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
  0x0c0880000c40: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
=>0x0c0880000c50: fa fa 00 00 00 00 04 fa fa fa[fd]fd fd fd fd fa
  0x0c0880000c60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0880000c70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0880000c80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0880000c90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0880000ca0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==1989454==ABORTING

Requires USE_ZEND_ALLOC=0

PHP Version

PHP 8.5.0-dev

Operating System

No response

Activity

  1. iluuu1994 commented on Oct 30, 2024

    @iluuu1994
    Member

    Hi @chibinz. Note that we have gotten lots of reports for ArrayObject from fuzzers. The class is fundamentally broken and weird, and we should look into deprecating/removing it in the near future. It likely doesn't make too much sense to run fuzzers on it.

  2. chibinz commented on Oct 30, 2024

    @chibinz
    Author

    I see, thanks for the notice. I exclude ArrayObjects bugs from my reports. Should I close this issue?

  3. cmb69 commented on Oct 30, 2024

    @cmb69
    Member

    The class is fundamentally broken and weird, and we should look into deprecating/removing it in the near future.

    Well, @arnaud-lb made the point that the class is likely only broken when wrapping objects; wrapping arrays may still be fine, and can be useful.

  4. arnaud-lb commented on Oct 30, 2024

    @arnaud-lb
    Member

    I also believe that wrapping arrays was the intended use-case: #16371 (comment)

  5. cmb69 commented on Oct 30, 2024

    @cmb69
    Member

    @chibinz, so maybe keep fuzzing ArrayObject, but only if it wraps arrays, but not objects.

  6. ndossche commented on Oct 30, 2024

    @ndossche
    Member

    This particular issue can be fixed by setting a "write locked" flag and checking that flag in write methods. Similar to what I did in https://github.com/php/php-src/pull/16346/files
    ArrayObject or not, any container class can have this issue.

  7. added a commit that references this issue on Oct 30, 2024
    67e2929
  8. iluuu1994 commented on Oct 30, 2024

    @iluuu1994
    Member

    @nielsdos We've fixed issues in other containers recently (e.g. GH-16481). But fair enough. The fix is easy, and it might be possible to trigger similar issues by wrapping the object with the destructor in an array. I created a PR here: GH-16653

  9. added a commit that references this issue on Nov 4, 2024
    8910ac8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions