Fix buffer overflow (pull request #81)

This commit is contained in:
Giancarlo Canales Barreto
2015-06-10 21:31:22 +02:00
committed by Benoit Blanchon
parent 08d05df00e
commit 5e7b9ec688
3 changed files with 32 additions and 17 deletions

View File

@ -1,6 +1,13 @@
Arduino JSON: change log Arduino JSON: change log
======================== ========================
v4.5
----
* Fixed buffer overflow when input contains a backslash followed by a terminator (issue #81)
**Upgrading is recommended** since previous versions contain a potential security risk.
v4.4 v4.4
---- ----

View File

@ -58,46 +58,44 @@ static char unescapeChar(char c) {
static inline bool isQuote(char c) { return c == '\"' || c == '\''; } static inline bool isQuote(char c) { return c == '\"' || c == '\''; }
char *QuotedString::extractFrom(char *input, char **endPtr) { char *QuotedString::extractFrom(char *input, char **endPtr) {
char firstChar = *input;
if (!isQuote(firstChar)) {
// must start with a quote
return NULL;
}
char stopChar = firstChar; // closing quote is the same as opening quote
char *startPtr = input + 1; // skip the quote char *startPtr = input + 1; // skip the quote
char *readPtr = startPtr; char *readPtr = startPtr;
char *writePtr = startPtr; char *writePtr = startPtr;
char c; char c;
char firstChar = *input;
char stopChar = firstChar; // closing quote is the same as opening quote
if (!isQuote(firstChar)) goto ERROR_OPENING_QUOTE_MISSING;
for (;;) { for (;;) {
c = *readPtr++; c = *readPtr++;
if (c == '\0') { if (c == '\0') goto ERROR_CLOSING_QUOTE_MISSING;
// premature ending
return NULL;
}
if (c == stopChar) { if (c == stopChar) goto SUCCESS;
// closing quote
break;
}
if (c == '\\') { if (c == '\\') {
// replace char // replace char
c = unescapeChar(*readPtr++); c = unescapeChar(*readPtr++);
if (c == '\0') goto ERROR_ESCAPE_SEQUENCE_INTERRUPTED;
} }
*writePtr++ = c; *writePtr++ = c;
} }
SUCCESS:
// end the string here // end the string here
*writePtr = '\0'; *writePtr = '\0';
// update end ptr // update end ptr
*endPtr = readPtr; *endPtr = readPtr;
// return pointer to unquoted string
return startPtr; return startPtr;
ERROR_OPENING_QUOTE_MISSING:
ERROR_CLOSING_QUOTE_MISSING:
ERROR_ESCAPE_SEQUENCE_INTERRUPTED:
return NULL;
} }

View File

@ -16,6 +16,11 @@ class QuotedString_ExtractFrom_Tests : public testing::Test {
_result = QuotedString::extractFrom(_jsonString, &_trailing); _result = QuotedString::extractFrom(_jsonString, &_trailing);
} }
void whenInputIs(const char *json, size_t len) {
memcpy(_jsonString, json, len);
_result = QuotedString::extractFrom(_jsonString, &_trailing);
}
void resultMustBe(const char *expected) { EXPECT_STREQ(expected, _result); } void resultMustBe(const char *expected) { EXPECT_STREQ(expected, _result); }
void trailingMustBe(const char *expected) { void trailingMustBe(const char *expected) {
@ -134,3 +139,8 @@ TEST_F(QuotedString_ExtractFrom_Tests, AllEscapedCharsTogether) {
whenInputIs("\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\""); whenInputIs("\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"");
resultMustBe("1\"2\\3/4\b5\f6\n7\r8\t9"); resultMustBe("1\"2\\3/4\b5\f6\n7\r8\t9");
} }
TEST_F(QuotedString_ExtractFrom_Tests, UnterminatedEscapeSequence) {
whenInputIs("\"\\\0\"", 4);
resultMustBe(0);
}