Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • A ArduinoJson
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 24
    • Issues 24
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Benoît Blanchon
  • ArduinoJson
  • Merge requests
  • !81

Update QuotedString.cpp

  • Review changes

  • Download
  • Email patches
  • Plain diff
Closed Administrator requested to merge master-81 into master Jun 10, 2015
  • Overview 7
  • Commits 1
  • Pipelines 0
  • Changes 1

Created by: ghost

After seeing how useful this library has proven to be to within the Arduino community, I decided to fuzz the parser.

All the fuzzing and testing was done in a Linux x64 environment, using AFL and LLVM's AddressSanitizer in order to hunt for weird behavior.

Shortly after beginning to fuzz the parser, I encountered a crash with the following sequence:

00000000  7b 22 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |{"              |
00000010  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
*
00000030  33 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |3               |
00000040  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
00000050  20 20 20 20 20 20 20 20  20 76 20 20 20 20 20 20  |         v      |
00000060  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
*
00000080  20 33 20 20 20 20 20 20  20 20 20 20 20 20 20 20  | 3              |
00000090  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
*
000000e0  20 20 20 4b 5c 5c 5c 00                           |   K\\\.|
000000e7

This interesting sequence produces a buffer over-read and overflow in the stack or heap, depending on where the JSON string is located, and can cause memory corruptions that crash the program.

The culprit is the escaped characters at the end of the quoted string, they cause the extractFrom function to miss the NULL terminator on the next cycle.

The original extractFrom code is as follows:

char *QuotedString::extractFrom(char *input, char **endPtr) {
  ...
  for (;;) {
    c = *readPtr++;

    if (c == '\0') {
      // premature ending
      return NULL;
    }

    if (c == stopChar) {
      // closing quote
      break;
    }

>>>
    if (c == '\\') {
      // replace char
      c = unescapeChar(*readPtr++);
    }
>>>

    *writePtr++ = c;
  }
  ...
}

As you can see, this operation will eventually lead the NULL check to miss the string's null terminator, effectively causing a buffer over-read and overflow which can lead to security issues.

In order to illustrate the issue, let [] denote the pointer position, let ! denote NULL, and let this be the pointer state:

"[\]\\!"

The unescapeChar function will move the pointer to:

"\[\]\!"

At the beginning of the next cycle, the pointer will move one more step to:

"\\[\]!"

And the unescapeChar function will once again move the pointer to:

"\\\[!]"

And, finally, at the beginning of the next cycle, the pointer will move and skip the null terminator:

"\\\![]"

The fix I propose simply checks to see if we've reached a premature ending after unescaping the character:

--- a/src/Internals/QuotedString.cpp
+++ b/src/Internals/QuotedString.cpp
@@ -73,6 +73,7 @@ char *QuotedString::extractFrom(char *input, char **endPtr) {
   char c;

   for (;;) {
     c = *readPtr++;

     if (c == '\0') {
@@ -90,6 +91,11 @@ char *QuotedString::extractFrom(char *input, char **endPtr) {
       c = unescapeChar(*readPtr++);
     }

+    if (c == '\0') {
+      // premature ending
+      return NULL;
+    }
+
     *writePtr++ = c;
   }

The ArduinoJson library passes all built-in tests with this fix.

Assignee
Assign to
Reviewers
Request review from
Time tracking
Source branch: master-81