Skip to content

JIT constant/enum case use-after-free in Laravel tests #12366

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
iluuu1994 opened this issue Oct 5, 2023 · 3 comments
Closed

JIT constant/enum case use-after-free in Laravel tests #12366

iluuu1994 opened this issue Oct 5, 2023 · 3 comments

Comments

@iluuu1994
Copy link
Member

Description

https://github.com/php/php-src/actions/runs/6413467433/job/17412449661

php-dev -d opcache.enable_cli=1 -d opcache.jit=tracing -d opcache.jit_buffer_size=1G -d opcache.jit_max_root_traces=1000000 -d opcache.jit_max_side_traces=1000000 -d opcache.jit_max_exit_counters=1000000 -d opcache.jit_hot_loop=1 -d opcache.jit_hot_func=1 -d opcache.jit_hot_return=1 -d opcache.jit_hot_side_exit=1 -d memory_limit=-1 vendor/bin/phpunit --exclude-group skip

 =================================================================
==221557==ERROR: AddressSanitizer: heap-use-after-free on address 0x6040005392d4 at pc 0x562f58d72180 bp 0x7ffe209c3020 sp 0x7ffe209c3010
READ of size 4 at 0x6040005392d4 thread T0
    #0 0x562f58d7217f in zend_string_release /home/runner/work/php-src/php-src/Zend/zend_string.h:322
    #1 0x562f58d90c56 in zend_hash_destroy /home/runner/work/php-src/php-src/Zend/zend_hash.c:1733
    #2 0x562f58cb1e03 in destroy_zend_class /home/runner/work/php-src/php-src/Zend/zend_opcode.c:405
    #3 0x562f58c8d7b2 in shutdown_executor /home/runner/work/php-src/php-src/Zend/zend_execute_API.c:454
    #4 0x562f58d0c836 in zend_deactivate /home/runner/work/php-src/php-src/Zend/zend.c:1259
    #5 0x562f589986cd in php_request_shutdown /home/runner/work/php-src/php-src/main/main.c:1863
    #6 0x562f5950a644 in do_cli /home/runner/work/php-src/php-src/sapi/cli/php_cli.c:1135
    #7 0x562f5950b95d in main /home/runner/work/php-src/php-src/sapi/cli/php_cli.c:1333
    #8 0x7f49282ee082 in __libc_start_main (/usr/lib/x86_64-linux-gnu/libc.so.6+0x24082)
    #9 0x562f56a134bd in _start (/usr/bin/php+0x40134bd)

0x6040005392d4 is located 4 bytes inside of 40-byte region [0x6040005392d0,0x6040005392f8)
freed by thread T0 here:
    #0 0x7f492ce5f40f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:122
    #1 0x562f58bc9975 in tracked_free /home/runner/work/php-src/php-src/Zend/zend_alloc.c:2853
    #2 0x562f58bc6c5d in _efree_custom /home/runner/work/php-src/php-src/Zend/zend_alloc.c:2488
    #3 0x562f58bc7293 in _efree /home/runner/work/php-src/php-src/Zend/zend_alloc.c:2608
    #4 0x562f58cfb38e in zend_string_destroy /home/runner/work/php-src/php-src/Zend/zend_variables.c:67
    #5 0x562f58cfb04b in rc_dtor_func /home/runner/work/php-src/php-src/Zend/zend_variables.c:57
    #6 0x562f58cfadd3 in i_zval_ptr_dtor /home/runner/work/php-src/php-src/Zend/zend_variables.h:44
    #7 0x562f58cfb4e4 in zval_ptr_dtor /home/runner/work/php-src/php-src/Zend/zend_variables.c:84
    #8 0x562f58d8fe91 in zend_hash_destroy /home/runner/work/php-src/php-src/Zend/zend_hash.c:1684
    #9 0x562f58c7e32a in zend_hash_release /home/runner/work/php-src/php-src/Zend/zend_hash.h:374
    #10 0x562f58c89c80 in zend_shutdown_executor_values /home/runner/work/php-src/php-src/Zend/zend_execute_API.c:355
    #11 0x562f58c8b7af in shutdown_executor /home/runner/work/php-src/php-src/Zend/zend_execute_API.c:416
    #12 0x562f58d0c836 in zend_deactivate /home/runner/work/php-src/php-src/Zend/zend.c:1259
    #13 0x562f589986cd in php_request_shutdown /home/runner/work/php-src/php-src/main/main.c:1863
    #14 0x562f5950a644 in do_cli /home/runner/work/php-src/php-src/sapi/cli/php_cli.c:1135
    #15 0x562f5950b95d in main /home/runner/work/php-src/php-src/sapi/cli/php_cli.c:1333
    #16 0x7f49282ee082 in __libc_start_main (/usr/lib/x86_64-linux-gnu/libc.so.6+0x24082)

previously allocated by thread T0 here:
    #0 0x7f492ce5f808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
    #1 0x562f58bc9612 in tracked_malloc /home/runner/work/php-src/php-src/Zend/zend_alloc.c:2834
    #2 0x562f58bc693c in _malloc_custom /home/runner/work/php-src/php-src/Zend/zend_alloc.c:2479
    #3 0x562f58bc70bb in _emalloc /home/runner/work/php-src/php-src/Zend/zend_alloc.c:2598
    #4 0x562f58aa2928 in zend_string_alloc /home/runner/work/php-src/php-src/Zend/zend_string.h:152
    #5 0x562f58aa2b46 in zend_string_init /home/runner/work/php-src/php-src/Zend/zend_string.h:174
    #6 0x562f58b6a4e6 in lex_scan Zend/zend_language_scanner.l:3103
    #7 0x562f58bed3eb in zendlex /home/runner/work/php-src/php-src/Zend/zend_compile.c:1838
    #8 0x562f58a866ff in zendparse /home/runner/work/php-src/php-src/Zend/zend_language_parser.c:4664
    #9 0x562f58aafc75 in zend_compile Zend/zend_language_scanner.l:600
    #10 0x562f58ab0c73 in compile_file Zend/zend_language_scanner.l:654
    #11 0x562f57c25938 in phar_compile_file /home/runner/work/php-src/php-src/ext/phar/phar.c:3355
    #12 0x7f492295106c in persistent_compile_file /home/runner/work/php-src/php-src/ext/opcache/ZendAccelerator.c:2168
    #13 0x562f58ab1c25 in compile_filename Zend/zend_language_scanner.l:705
    #14 0x562f58e303f5 in zend_include_or_eval /home/runner/work/php-src/php-src/Zend/zend_execute.c:4799
    #15 0x562f5905f005 in ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER /home/runner/work/php-src/php-src/Zend/zend_vm_execute.h:38961
    #16 0x562f5912a016 in execute_ex /home/runner/work/php-src/php-src/Zend/zend_vm_execute.h:59408
    #17 0x562f58c96c50 in zend_call_function /home/runner/work/php-src/php-src/Zend/zend_execute_API.c:949
    #18 0x562f58c98e22 in zend_call_known_function /home/runner/work/php-src/php-src/Zend/zend_execute_API.c:1043
    #19 0x562f58056fd4 in spl_perform_autoload /home/runner/work/php-src/php-src/ext/spl/php_spl.c:445
    #20 0x562f58c9b672 in zend_lookup_class_ex /home/runner/work/php-src/php-src/Zend/zend_execute_API.c:1209
    #21 0x562f58c9e928 in zend_fetch_class_by_name /home/runner/work/php-src/php-src/Zend/zend_execute_API.c:1705
    #22 0x562f58ea7de7 in ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_CONST_HANDLER /home/runner/work/php-src/php-src/Zend/zend_vm_execute.h:7148
    #23 0x562f591184a8 in execute_ex /home/runner/work/php-src/php-src/Zend/zend_vm_execute.h:56658
    #24 0x562f591308ad in zend_execute /home/runner/work/php-src/php-src/Zend/zend_vm_execute.h:60409
    #25 0x562f58d15410 in zend_execute_scripts /home/runner/work/php-src/php-src/Zend/zend.c:1833
    #26 0x562f5899d6fd in php_execute_script /home/runner/work/php-src/php-src/main/main.c:2542
    #27 0x562f59508568 in do_cli /home/runner/work/php-src/php-src/sapi/cli/php_cli.c:964
    #28 0x562f5950b95d in main /home/runner/work/php-src/php-src/sapi/cli/php_cli.c:1333
    #29 0x7f49282ee082 in __libc_start_main (/usr/lib/x86_64-linux-gnu/libc.so.6+0x24082)

SUMMARY: AddressSanitizer: heap-use-after-free /home/runner/work/php-src/php-src/Zend/zend_string.h:322 in zend_string_release
Shadow bytes around the buggy address:
  0x0c088009f200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c088009f210: fa fa 00 00 00 00 00 fa fa fa fa fa fa fa fa fa
  0x0c088009f220: fa fa 00 00 00 00 00 00 fa fa fd fd fd fd fd fd
  0x0c088009f230: fa fa 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
  0x0c088009f240: fa fa 00 00 00 00 00 00 fa fa fd fd fd fd fd fd
=>0x0c088009f250: fa fa 00 00 00 00 00 fa fa fa[fd]fd fd fd fd fa
  0x0c088009f260: fa fa fd fd fd fd fd fa fa fa fa fa fa fa fa fa
  0x0c088009f270: fa fa fa fa fa fa fa fa fa fa fd fd fd fd fd fd
  0x0c088009f280: fa fa 00 00 00 00 00 00 fa fa fd fd fd fd fd fd
  0x0c088009f290: fa fa 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
  0x0c088009f2a0: 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
  Shadow gap:              cc
==221557==ABORTING

I can't reproduce this issue with any specific test. Multiple tests must be at play. The issue is triggered when freeing the class Illuminate\Tests\Support\Fixtures\IntBackedEnum. The case name is stored in both the case object as well as the backed_enum_table as a key. However, for some reason the string is already released when freeing the backed enum table, indicating the refcount was too low. Since the use-after-free does not occur without JIT I'm assuming this is some refcounting issue somewhere in the jitted code (or in a JIT helper).

PHP Version

PHP 8.2+

Operating System

No response

@dstogov
Copy link
Member

dstogov commented Oct 9, 2023

I can reproduce the problem running only few unit tests

USE_ZEND_ALLOC=0 php-dev -n -d zend_extension=opcache.so -d opcache.enable_cli=1 -d opcache.jit=tracing -d opcache.jit_buffer_size=1G -d opcache.jit_max_root_traces=1000000 -d opcache.jit_max_side_traces=1000000 -d opcache.jit_max_exit_counters=1000000 -d opcache.jit_hot_loop=1 -d opcache.jit_hot_func=1 -d opcache.jit_hot_return=1 -d opcache.jit_hot_side_exit=1 -d memory_limit=-1 vendor/bin/phpunit tests/Integration/Queue --exclude-group skip

However the problem is not directly related to JIT. This's PHP enum implementation problem triggered by out of shared memory. Adding -d opcache.memory_consumption=256 fixes the problem.

The problem occurs because we reserve big amount of shared memory for root traces (88M out of default 128M). Then some script can't be cached in opcache and some interned strings (used as enum cases later) are not created. And then during compilation of enum, in zend_compile_enum_case(), zval_make_interned_string() returns non-interned string.

@iluuu1994 can you please take care about this.

@danog it make sense to increase opcache.memory_consumption for your PR.

@dstogov
Copy link
Member

dstogov commented Oct 9, 2023

A simpler test case:

<?php
enum Level: int {
    case Debug = 100;
}
var_dump(Level::Debug);
?>

USE_ZEND_ALLOC=0 sapi/cli/php -d opcache.memory_consumption=32 -d opcache.jit_max_root_traces=214524 -d opcache.jit=0 x.php

jit_max_root_traces setting is especially selected to allocate all shm, but it may be build-dependent.

@iluuu1994
Copy link
Member Author

@dstogov Thank you for the simplified case, I'll have a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants