Skip to content

Assertion failure in ReflectionProperty::isReadable() with by-reference __isset() #22000

@kid-lxy

Description

@kid-lxy

Description

The following code:

<?php

class A {
    public $a;
    public int $b;
    public int $c = 42;
    public int $d;
    public int $e;

    public function __construct() {
        unset($this->e);
    }
}

class B {
    public int $f;
    public int $g;
    public int $h;

    public function __construct() {
        unset($this->g);
        unset($this->h);
    }

    public function&__isset($name) {
        return $name === 'h';
    }

    public function __get($name) {}
}

class C {
    public int $i;
    public int $j;
    public int $k;

    public function __construct() {
        unset($this->j);
        unset($this->k);
    }

    public function __get($name) {}
}

function test($class) {
    $rc = new ReflectionClass($class);
    foreach ($rc->getProperties() as $rp) {
        echo $rp->getName() . ' from global: ';
        var_dump($rp->isReadable(null, new $class));
    }
}

test('A');
test('B');
test('C');

Resulted in this output:

php-fuzz-execute: /home/kid/php_newest/Zend/zend_vm_execute.h:2161: const zend_op *ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER(zend_execute_data *, const zend_op *): Assertion `(call->func->common.fn_flags & (1 << 12)) ? (zval_get_type(&(*(ret))) == 10) : !(zval_get_type(&(*(ret))) == 10)' failed.
==69783== ERROR: libFuzzer: deadly signal
    #0 0x5bf1954dd715 in __sanitizer_print_stack_trace (/home/kid/php_newest/sapi/fuzzer/php-fuzz-execute+0x38dd715) (BuildId: 0d5597bf0ebd2525add5014f4baf69af768a9c63)
    #1 0x5bf19543722c in fuzzer::PrintStackTrace() (/home/kid/php_newest/sapi/fuzzer/php-fuzz-execute+0x383722c) (BuildId: 0d5597bf0ebd2525add5014f4baf69af768a9c63)
    #2 0x5bf19541d2b7 in fuzzer::Fuzzer::CrashCallback() (/home/kid/php_newest/sapi/fuzzer/php-fuzz-execute+0x381d2b7) (BuildId: 0d5597bf0ebd2525add5014f4baf69af768a9c63)
    #3 0x78909e84532f  (/lib/x86_64-linux-gnu/libc.so.6+0x4532f) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
    #4 0x78909e89eb2b in __pthread_kill_implementation nptl/pthread_kill.c:43:17
    #5 0x78909e89eb2b in __pthread_kill_internal nptl/pthread_kill.c:78:10
    #6 0x78909e89eb2b in pthread_kill nptl/pthread_kill.c:89:10
    #7 0x78909e84527d in raise signal/../sysdeps/posix/raise.c:26:13
    #8 0x78909e8288fe in abort stdlib/abort.c:79:7
    #9 0x78909e82881a in __assert_fail_base assert/assert.c:96:3
    #10 0x78909e83b516 in __assert_fail assert/assert.c:105:3
    #11 0x5bf19a8ebdbe in ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER /home/kid/php_newest/Zend/zend_vm_execute.h:2160:4
    #12 0x5bf19b6e0920 in fuzzer_execute_ex /home/kid/php_newest/sapi/fuzzer/fuzzer-execute-common.h:65:12
    #13 0x5bf19a8e4e15 in ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER /home/kid/php_newest/Zend/zend_vm_execute.h:1990:4
    #14 0x5bf19b6e0920 in fuzzer_execute_ex /home/kid/php_newest/sapi/fuzzer/fuzzer-execute-common.h:65:12
    #15 0x5bf19a5696cf in zend_execute /home/kid/php_newest/Zend/zend_vm_execute.h:115586:2
    #16 0x5bf19b6e4136 in fuzzer_do_request_from_buffer /home/kid/php_newest/sapi/fuzzer/fuzzer-sapi.c:293:5
    #17 0x5bf19b6e03b9 in LLVMFuzzerTestOneInput /home/kid/php_newest/sapi/fuzzer/fuzzer-execute.c:25:2

This seems to happen because ReflectionProperty::isReadable() forwards the result of __isset() directly without validation, so a by-reference return can leak into a non-reference return slot.

PHP Version

find in the commit c417deaf0f6e0a44da2315dd631b2f918a295782
and it still crashed in the latest commit

Operating System

Ubuntu 24.04

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