Skip to content

PHP Fatal error: Maximum function nesting level of '256' reached, aborting! Protocol/Parser.php on line 293 #114

Closed

Description

@wxiaoguang

When feed invalid data to Parser, we meet the fatal error.

Test data: hex2bin('80000000016db558016de4c8000000000000000400000001461fffff000005dc000020000000000137cdfa4000000000')

It is caused by the call between readLabels and getCompressedLabel


PHP 242. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 243. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 244. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 245. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 246. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 247. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 248. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 249. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 250. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 251. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 252. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 253. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 254. React\Dns\Protocol\Parser->readLabels($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:273
PHP 255. React\Dns\Protocol\Parser->getCompressedLabel($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:245
PHP 256. React\Dns\Protocol\Parser->getCompressedLabelOffset($data = *uninitialized*, $consumed = *uninitialized*) Protocol/Parser.php:272
    private function readLabels($data, $consumed)
    {
        $labels = array();

        while (true) {
            if ($this->isEndOfLabels($data, $consumed)) {
                $consumed += 1;
                break;
            }

            if ($this->isCompressedLabel($data, $consumed)) {
                list($newLabels, $consumed) = $this->getCompressedLabel($data, $consumed);
                $labels = array_merge($labels, $newLabels);
                break;
            }

Activity

  1. clue commented on Nov 1, 2018

    @clue
    Member

    @wxiaoguang Thanks for reporting and providing the test case! I can confirm this bug and will look into this 👍

    Out of interest, where does this data come from? What (part of a) message does it represent?

  2. added and removed on Nov 1, 2018
  3. added this to the v0.4.16 milestone on Nov 1, 2018
  4. wxiaoguang commented on Nov 2, 2018

    @wxiaoguang
    Author

    I am using ReactDns to parse the sniffed logs of tcpdump. There are many non-dns traffics on port 53.

    Besides this fatal error, there are also many E_ERROR/E_WARNING/E_NOTICE errors when using ReactDns to parse invalid data. These errors are mainly caused by unchecked array access, unpack insufficiency data, invalid inet_pton, etc. I can ignore these non-fatal errors, but I must bypass this fatal error to complete my work :D (I just made a very very dirty hack to bypass this fatal error: use a static $depth to count the recursion calls, when depth is big enough, return an error).

  5. clue commented on Nov 5, 2018

    @clue
    Member

    @wxiaoguang Again, thank you for reporting and giving this background info!

    We've just fixed this fatal error when parsing malformed response messages with #115 and I've filed #117 to fix any non-fatal errors when parsing malformed response messages. Once this PR is merged, you should no longer see any of the parsing errors you've mentioned.

  6. holtkamp commented on Sep 15, 2020

    @holtkamp

    It seems I have encountered this problem as well when crawling a big XML sitemap on a daily basis using https://github.com/dpovshed/octopus

    Error: Maximum function nesting level of '256' reached, aborting! in /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php on line 313
    
    Call Stack:
        0.0594     397776   1. {main}() /project/my-sitemap-crawler/application.php:0
        1.0780     979392   2. {closure:/project/my-sitemap-crawler/application.php:16-33}() /project/my-sitemap-crawler/application.php:33
        1.6803    1987616   3. Symfony\Component\Console\Application->run() /project/my-sitemap-crawler/application.php:32
        1.8856    2236896   4. Symfony\Component\Console\Application->doRun() /project/my-sitemap-crawler/vendor/symfony/console/Application.php:140
        1.9937    2314696   5. Symfony\Component\Console\Application->doRunCommand() /project/my-sitemap-crawler/vendor/symfony/console/Application.php:264
        1.9938    2314696   6. Octopus\Command\RunOctopusCommand->run() /project/my-sitemap-crawler/vendor/symfony/console/Application.php:916
        1.9945    2317312   7. Octopus\Command\RunOctopusCommand->execute() /project/my-sitemap-crawler/vendor/symfony/console/Command/Command.php:258
        3.2297    2931240   8. Octopus\Processor->run() /project/my-sitemap-crawler/vendor/octopoda/octopus/src/Command/RunOctopusCommand.php:127
        3.2297    2931240   9. React\EventLoop\StreamSelectLoop->run() /project/my-sitemap-crawler/vendor/octopoda/octopus/src/Processor.php:99
     1901.5412   45575736  10. React\EventLoop\StreamSelectLoop->waitForStreamActivity() /project/my-sitemap-crawler/vendor/react/event-loop/src/StreamSelectLoop.php:212
     1901.5412   45576176  11. React\Dns\Query\UdpTransportExecutor->React\Dns\Query\{closure:/project/my-sitemap-crawler/vendor/react/dns/src/Query/UdpTransportExecutor.php:152-184}() /project/my-sitemap-crawler/vendor/react/event-loop/src/StreamSelectLoop.php:245
     1901.5413   45576336  12. React\Dns\Protocol\Parser->parseMessage() /project/my-sitemap-crawler/vendor/react/dns/src/Query/UdpTransportExecutor.php:158
     1901.5413   45577288  13. React\Dns\Protocol\Parser->parse() /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php:31
     1901.5413   45577288  14. React\Dns\Protocol\Parser->parseQuestion() /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php:60
     1901.5413   45577288  15. React\Dns\Protocol\Parser->readLabels() /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php:109
     1901.5413   45577792  16. React\Dns\Protocol\Parser->readLabels() /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php:329
     1901.5413   45578232  17. React\Dns\Protocol\Parser->readLabels() /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php:329
     1901.5413   45578672  18. React\Dns\Protocol\Parser->readLabels() /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php:329
     1901.5413   45579112  19. React\Dns\Protocol\Parser->readLabels() /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php:329
     ....
     1901.5439   45682072 253. React\Dns\Protocol\Parser->readLabels() /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php:329
     1901.5439   45682512 254. React\Dns\Protocol\Parser->readLabels() /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php:329
     1901.5439   45682952 255. React\Dns\Protocol\Parser->readLabels() /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php:329
     1901.5439   45683392 256. React\Dns\Protocol\Parser->readLabels() /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php:329
    

    The challenge is: it does not occur every day, so I will try to gather some more information. I have the feeling that it happens when (multiple) invalid domains are crawled, for example:

    https://crazySubDomainWhichDoesNotExist.example.com
    https://crazySubDomainWhichDoesNotExist2.example.com
    https://crazySubDomainWhichDoesNotExistN.example.com

    @clue do you have any advise on where I can start looking / which information needs to be collected?

  7. clue commented on Sep 16, 2020

    @clue
    Member

    @holtkamp Thanks for reporting, this shouldn't have happened!

    I don't think this is related to the original issue discussed here, can you file this as a separate ticket?

    Ideally, the stack trace should include method arguments or a Wireshark/tcpdump trace would help a lot to trace this down.

  8. holtkamp commented on Sep 16, 2020

    @holtkamp

    @clue sure, first I will investigate further and check whether "ensuring the sitemap only contains valid links" prevents the issue from occurring, that would already narrow the possible source of the problem down a bit.

  9. clue commented on Sep 24, 2020

    @clue
    Member

    @holtkamp I've managed to reproduce and fix this for malformed DNS response messages via #169. This only affects malformed/crafted DNS responses, I don't see how this could affect a valid DNS response message that would occur in the wild. Perhaps you can give this a try and see if this solves your problem?

  10. holtkamp commented on Sep 24, 2020

    @holtkamp

    @clue thanks for the quick follow-up. I did not have time to dive into this in detail, but I did collect some additional error messages which contain some CLUEs 😄 :

    PHP Fatal error:  Uncaught Error: Maximum function nesting level of '256' reached, aborting! in /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php:313
    Stack trace:
    #0 /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php(313): ord('!')
    #1 /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php(329): React\Dns\Protocol\Parser->readLabels('\x00<\x00\x044\xD6\xAB@\xC06\x00\x01\x00\x01\x00...', 54)
    #2 /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php(329): React\Dns\Protocol\Parser->readLabels('\x00<\x00\x044\xD6\xAB@\xC06\x00\x01\x00\x01\x00...', 90)
    #3 /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php(329): React\Dns\Protocol\Parser->readLabels('\x00<\x00\x044\xD6\xAB@\xC06\x00\x01\x00\x01\x00...', 90)
    #4 /project/ in /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php on line 313
    
    PHP Fatal error:  Uncaught Error: Maximum function nesting level of '256' reached, aborting! in /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php:313
    Stack trace:
    #0 /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php(313): ord('\x01')
    #1 /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php(329): React\Dns\Protocol\Parser->readLabels('=\x00\x01\x00\x01\x00\x00\x00-\x00\x0440K\xF6...', 61)
    #2 /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php(329): React\Dns\Protocol\Parser->readLabels('=\x00\x01\x00\x01\x00\x00\x00-\x00\x0440K\xF6...', 65)
    #3 /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php(329): React\Dns\Protocol\Parser->readLabels('=\x00\x01\x00\x01\x00\x00\x00-\x00\x0440K\xF6...', 65)
    #4 /project/ in /project/my-sitemap-crawler/vendor/react/dns/src/Protocol/Parser.php on line 313
    

    Unfortunately the first parameter of Parser::readLabels() in the error message is truncated, but maybe it helps in confirming that your suggested fix works?

    I will use https://github.com/clue-labs/dns/tree/compression-recurse, monitor the daily crawls and report back here.

  11. clue commented on Sep 24, 2020

    @clue
    Member

    @holtkamp The second argument in the trace is interesting, it suggests it finds a compressed DNS pointer that points to itself, thus leading to the infinite recursion. I don't see this specific scenario covered in the specs (https://tools.ietf.org/html/rfc1035#section-4.1.4), but it's my understanding this should be an invalid pointer that should never happen in the wild. The updated version would successfully reject the promise to show an invalid response message in this case.

    If you can reproduce this, please let me know the hostname and/or DNS server in question (here or DM) so I can see how others handle this situation.

  12. holtkamp commented on Sep 25, 2020

    @holtkamp

    @clue it seems #169 indeed prevents the problem from occurring 🚀

    Will keep monitoring and report my findings here after the weekend!

    BTW: kudos that you understand and implement such "low-level" protocols: https://tools.ietf.org/html/rfc1035#section-4.1.4 🤓

  13. holtkamp commented on Sep 28, 2020

    @holtkamp

    @clue the sitemap crawls during last weekend did not have any problems anymore, so I would "assume" #169 fixes the issue indeed. I do not have hard evidence other than "no errors occurred", will keep monitoring, but +1 for merging it to master and tagging a new release 😉

  14. holtkamp commented on Oct 28, 2020

    @holtkamp

    @clue FYI: we have been monitoring the daily sitemap crawls and no more problems have occurred for a month.

    Will coming Friday be release-day for 1.5.0? 😇

  15. holtkamp commented on Nov 12, 2020

    @holtkamp

    @clue don't want to harass, but this probably slipped from your radar?

  16. clue commented on Nov 14, 2020

    @clue
    Member

    @holtkamp Don't worry, didn't forget about this one and will get back to this as soon as time permits 👍

    Currently working on a number of higher priority (paid) projects, but will look into the release afterwards.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions