Skip to content

Internal exceptions may misinterpret the null byte \0 #10810

Closed
@b-viguier

Description

@b-viguier

Description

The following code:

<?php

throw new \Exception("Hello\0World");

Resulted in this output:

Fatal error: Uncaught Exception: Hello in /tmp/preview:3
Stack trace:
#0 {main}
  thrown in /tmp/preview on line 3

But I expected this output instead:

Fatal error: Uncaught Exception: HelloWorld in /tmp/preview:3
Stack trace:
#0 {main}
  thrown in /tmp/preview on line 3

or

Fatal error: Uncaught Exception: Hello\x00World in /tmp/preview:3
Stack trace:
#0 {main}
  thrown in /tmp/preview on line 3

Notes

Thanks to this strange behavior, I discovered that Zend strings are perfectly able to handle the \0 character.
But to call the function zend_throw_exception(zend_class_entry *exception_ce, const char *message, zend_long code), some callers may convert a zend string to a raw C string, losing the actual size. Then, the newly created zend string will stop at the first \0, loosing the end of the string.

I didn't found any risk with this bug, since sensitive functions seem to look explicitly for this kind of abuse. Just to notice that some error messages may be truncated if they contain this null byte.

Here are some other examples:

<?php

call_user_func("Hello\0World");

$str = "Hello\0World";
new $str;

assert(false, "Hello\0World");

💡 It may be relevant to prefer the function zend_throw_exception_zstr when possible, to prevent to lose the actual length of the zend string.

Thanks for your amazing work 🙂 👍

PHP Version

PHP 8.0, 8.1, 8.2

Operating System

No response

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