php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #70290 Null pointer deref (segfault) in spl_autoload via ob_start
Submitted: 2015-08-18 10:24 UTC Modified: 2015-08-23 08:44 UTC
From: hugh at allthethings dot co dot nz Assigned: laruence (profile)
Status: Closed Package: Reproducible crash
PHP Version: 5.6.12 OS: Linux
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: hugh at allthethings dot co dot nz
New email:
PHP Version: OS:

 

 [2015-08-18 10:24 UTC] hugh at allthethings dot co dot nz
Description:
------------
Found this using afl-fuzz, see http://lcamtuf.coredump.cx/afl/

Affects 5.6.12, 5.5.28, (couldn't compile 5.4, and EOL is basically now so meh).

To reproduce, compile PHP normally, then run ./sapi/cli/php with the test script
<?php ob_start( spl_autoload ); ?> 1
You should get a segfault.

The test case required to have SOME output displayed to screen before the ob_start is called, hence the 1 at the end of the test script (only if a file called 9 exists in the current directory and is a valid php file with a class of no name (I had <?php class {} ?>... (this is because ob_start will call spl_autoload with an empty first argument (output buffer), and second argument of 9 (the phase)), otherwise if the file doesn't exist, removing the 1 will also make it crash. I've just included it here for completeness...).

The bug happens because if the spl_autoload doesn't load anything valid, then it tries to throw an exception, but in that test it uses active_opline, which is (*EG(opline_ptr)), which is (*(executor_state.opline_ptr)) or something, which is null.

Patch to fix would either be:
diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c
index 6b886b7..3424b90 100644
--- a/ext/spl/php_spl.c
+++ b/ext/spl/php_spl.c
@@ -358,7 +358,7 @@ PHP_FUNCTION(spl_autoload)
                 * The "scope" is determined by an opcode, if it is ZEND_FETCH_CLASS we know function was called indirectly by
                 * the Zend engine.
                 */
-               if (active_opline->opcode != ZEND_FETCH_CLASS) {
+               if (EG(opline_ptr) && active_opline->opcode != ZEND_FETCH_CLASS) {
                        zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Class %s could not be loaded", class_name);
                } else {
                        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s could not be loaded", class_name);


or some code to not let you use a internal function like that. Thoughts?



Test script:
---------------
<?php ob_start( spl_autoload ); ?> 1

Expected result:
----------------
No crash

Actual result:
--------------
(gdb) bt
#0  0x00000000004e4c02 in zif_spl_autoload (ht=2, return_value=0x7ffff7fe2940, 
    return_value_ptr=0x7fffffffd218, this_ptr=0x0, return_value_used=1)
    at /root/php-src/ext/spl/php_spl.c:361
#1  0x0000000000638aa3 in zend_call_function (fci=0x7ffff7fe3838, 
    fci_cache=0x7ffff7fe3880) at /root/php-src/Zend/zend_execute_API.c:847
#2  0x000000000065936e in zend_fcall_info_call (fci=0x7ffff7fe3838, 
    fcc=0x7ffff7fe3880, retval_ptr_ptr=0x7fffffffd218, args=0x0)
    at /root/php-src/Zend/zend_API.c:3397
#3  0x00000000005dc58d in php_output_handler_op (handler=0x7ffff7fe38c0, 
    context=0x7fffffffd2b0) at /root/php-src/main/output.c:977
#4  0x00000000005dcf2d in php_output_stack_pop (flags=1)
    at /root/php-src/main/output.c:1244
#5  0x00000000005db0da in php_output_end_all () at /root/php-src/main/output.c:351
#6  0x00000000005c515f in php_request_shutdown (dummy=0x0)
    at /root/php-src/main/main.c:1840
#7  0x000000000076ee5f in do_cli (argc=2, argv=0xb747c0)
    at /root/php-src/sapi/cli/php_cli.c:1177
#8  0x000000000076f67b in main (argc=2, argv=0xb747c0)
    at /root/php-src/sapi/cli/php_cli.c:1378
(gdb) i r
rax            0x0      0
rbx            0x7fffffffd218   140737488343576
rcx            0xffffffffffffff60       -160
rdx            0x6b8    1720
rsi            0x7ffff7fe2900   140737354017024
rdi            0xb74a80 12012160
rbp            0x7fffffffcec0   0x7fffffffcec0
rsp            0x7fffffffce40   0x7fffffffce40
r8             0x3      3
r9             0x7ffff74957b8   140737342166968
r10            0x7fffffffc970   140737488341360
r11            0x246    582
r12            0x418830 4294704
r13            0x7fffffffe9f0   140737488349680
r14            0x0      0
r15            0x0      0
rip            0x4e4c02 0x4e4c02 <zif_spl_autoload+514>
eflags         0x10246  [ PF ZF IF RF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) x/i $rip
=> 0x4e4c02 <zif_spl_autoload+514>:     mov    (%rax),%rax


With ASAN compiled
ASAN:SIGSEGV
=================================================================
==15374== ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x0000005f8f07 sp 0x7fffd148dd50 bp 0x7fffd148def0 T0)
AddressSanitizer can not provide additional info.
    #0 0x5f8f06 (/root/php-src/sapi/cli/php+0x5f8f06)
    #1 0x990c83 (/root/php-src/sapi/cli/php+0x990c83)
    #2 0x9ee97c (/root/php-src/sapi/cli/php+0x9ee97c)
    #3 0x88762b (/root/php-src/sapi/cli/php+0x88762b)
    #4 0x8891c7 (/root/php-src/sapi/cli/php+0x8891c7)
    #5 0x883d96 (/root/php-src/sapi/cli/php+0x883d96)
    #6 0x84be0a (/root/php-src/sapi/cli/php+0x84be0a)
    #7 0xd22665 (/root/php-src/sapi/cli/php+0xd22665)
    #8 0xd23c73 (/root/php-src/sapi/cli/php+0xd23c73)
    #9 0x7fcdef217ec4 (/lib/x86_64-linux-gnu/libc-2.19.so+0x21ec4)
    #10 0x418cf8 (/root/php-src/sapi/cli/php+0x418cf8)
==15374== ABORTING


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-08-19 10:49 UTC] laruence@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: laruence
 [2015-08-19 10:59 UTC] hugh at allthethings dot co dot nz
Will there be a CVE assigned for this?

Cheers,

Hugh
 [2015-08-23 05:42 UTC] stas@php.net
-Type: Security +Type: Bug
 [2015-08-23 05:42 UTC] stas@php.net
This doesn't look like a security issue, this is a specially crafted code which is extremely unlikely to happen in real application. So I do not think it needs a CVE.
 [2015-08-23 08:44 UTC] hugh at allthethings dot co dot nz
Hi stas,

No worries, next time!

Cheers,

Hugh
 [2015-09-03 18:10 UTC] ab@php.net
Automatic comment on behalf of laruence
Revision: http://git.php.net/?p=php-src.git;a=commit;h=b584b513983319be170f02828bc7c12850b40320
Log: Fixed bug #70290 (Null pointer deref (segfault) in spl_autoload via ob_start)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Dec 03 17:01:29 2024 UTC