-
Notifications
You must be signed in to change notification settings - Fork 636
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix potential buffer overflow in parseStringValue #152
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -354,28 +354,28 @@ bool isJsonValidAndParse(const char *pJsonDocument, void *pJsonHandler, int32_t | |
} | ||
|
||
static IoT_Error_t UpdateValueIfNoObject(const char *pJsonString, jsonStruct_t *pDataStruct, jsmntok_t token) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A look up table could look better. Though it is a risky change. |
||
IoT_Error_t ret_val = SUCCESS; | ||
if(pDataStruct->type == SHADOW_JSON_BOOL) { | ||
IoT_Error_t ret_val = SHADOW_JSON_ERROR; | ||
if(pDataStruct->type == SHADOW_JSON_BOOL && pDataStruct->dataLength >= sizeof(bool)) { | ||
ret_val = parseBooleanValue((bool *) pDataStruct->pData, pJsonString, &token); | ||
} else if(pDataStruct->type == SHADOW_JSON_INT32) { | ||
} else if(pDataStruct->type == SHADOW_JSON_INT32 && pDataStruct->dataLength >= sizeof(int32_t)) { | ||
ret_val = parseInteger32Value((int32_t *) pDataStruct->pData, pJsonString, &token); | ||
} else if(pDataStruct->type == SHADOW_JSON_INT16) { | ||
} else if(pDataStruct->type == SHADOW_JSON_INT16 && pDataStruct->dataLength >= sizeof(int16_t)) { | ||
ret_val = parseInteger16Value((int16_t *) pDataStruct->pData, pJsonString, &token); | ||
} else if(pDataStruct->type == SHADOW_JSON_INT8) { | ||
} else if(pDataStruct->type == SHADOW_JSON_INT8 && pDataStruct->dataLength >= sizeof(int8_t)) { | ||
ret_val = parseInteger8Value((int8_t *) pDataStruct->pData, pJsonString, &token); | ||
} else if(pDataStruct->type == SHADOW_JSON_UINT32) { | ||
} else if(pDataStruct->type == SHADOW_JSON_UINT32 && pDataStruct->dataLength >= sizeof(uint32_t)) { | ||
ret_val = parseUnsignedInteger32Value((uint32_t *) pDataStruct->pData, pJsonString, &token); | ||
} else if(pDataStruct->type == SHADOW_JSON_UINT16) { | ||
} else if(pDataStruct->type == SHADOW_JSON_UINT16 && pDataStruct->dataLength >= sizeof(uint16_t)) { | ||
ret_val = parseUnsignedInteger16Value((uint16_t *) pDataStruct->pData, pJsonString, &token); | ||
} else if(pDataStruct->type == SHADOW_JSON_UINT8) { | ||
} else if(pDataStruct->type == SHADOW_JSON_UINT8 && pDataStruct->dataLength >= sizeof(uint8_t)) { | ||
ret_val = parseUnsignedInteger8Value((uint8_t *) pDataStruct->pData, pJsonString, &token); | ||
} else if(pDataStruct->type == SHADOW_JSON_FLOAT) { | ||
} else if(pDataStruct->type == SHADOW_JSON_FLOAT && pDataStruct->dataLength >= sizeof(float)) { | ||
ret_val = parseFloatValue((float *) pDataStruct->pData, pJsonString, &token); | ||
} else if(pDataStruct->type == SHADOW_JSON_DOUBLE) { | ||
} else if(pDataStruct->type == SHADOW_JSON_DOUBLE && pDataStruct->dataLength >= sizeof(double)) { | ||
ret_val = parseDoubleValue((double *) pDataStruct->pData, pJsonString, &token); | ||
} else if(pDataStruct->type == SHADOW_JSON_STRING) { | ||
ret_val = parseStringValue((char *) pDataStruct->pData, pJsonString, &token); | ||
} | ||
ret_val = parseStringValue((char *) pDataStruct->pData, pDataStruct->dataLength, pJsonString, &token); | ||
} | ||
|
||
return ret_val; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,8 @@ | |
#include "aws_iot_tests_unit_helper_functions.h" | ||
#include "aws_iot_log.h" | ||
|
||
#define STRING_BUFFER_LENGTH (50) | ||
|
||
static IoT_Error_t rc = SUCCESS; | ||
|
||
static jsmn_parser test_parser; | ||
|
@@ -43,12 +45,12 @@ TEST_GROUP_C_TEARDOWN(JsonUtils) { | |
TEST_C(JsonUtils, ParseStringBasic) { | ||
int r; | ||
const char *json = "{\"x\":\"test1\"}"; | ||
char parsedString[50]; | ||
char parsedString[STRING_BUFFER_LENGTH]; | ||
|
||
IOT_DEBUG("\n-->Running Json Utils Tests - Basic String Parsing \n"); | ||
|
||
r = jsmn_parse(&test_parser, json, strlen(json), t, sizeof(t) / sizeof(t[0])); | ||
rc = parseStringValue(parsedString, json, t + 2); | ||
rc = parseStringValue(parsedString, STRING_BUFFER_LENGTH, json, t + 2); | ||
|
||
CHECK_EQUAL_C_INT(3, r); | ||
CHECK_EQUAL_C_INT(SUCCESS, rc); | ||
|
@@ -58,26 +60,48 @@ TEST_C(JsonUtils, ParseStringBasic) { | |
TEST_C(JsonUtils, ParseStringLongerStringIsValid) { | ||
int r; | ||
const char *json = "{\"x\":\"this is a longer string for test 2\"}"; | ||
char parsedString[50]; | ||
char parsedString[STRING_BUFFER_LENGTH]; | ||
|
||
IOT_DEBUG("\n-->Running Json Utils Tests - Parse long string \n"); | ||
|
||
r = jsmn_parse(&test_parser, json, strlen(json), t, sizeof(t) / sizeof(t[0])); | ||
rc = parseStringValue(parsedString, json, t + 2); | ||
rc = parseStringValue(parsedString, STRING_BUFFER_LENGTH, json, t + 2); | ||
|
||
CHECK_EQUAL_C_INT(3, r); | ||
CHECK_EQUAL_C_INT(SUCCESS, rc); | ||
CHECK_EQUAL_C_STRING("this is a longer string for test 2", parsedString); | ||
} | ||
|
||
/* Test that parsing a string doesn't overflow the given buffer. */ | ||
TEST_C(JsonUtils, ParseStringWithBufferTooSmall) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should test the happy path too :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like when the buffer is big enough? I think that's adequately tested by the integration tests (jobs integration test). |
||
static const char* const pJsonString = "{\"key\":\"This value is longer than JSON_BUFFER_LENGTH, which should be 50.\"}"; | ||
char parsedString[STRING_BUFFER_LENGTH] = {0}; | ||
int jsmnReturn, i; | ||
|
||
IOT_DEBUG("\n-->Running Json Utils Tests - String parsing with buffer too small. \n"); | ||
|
||
jsmnReturn = jsmn_parse(&test_parser, pJsonString, strlen(pJsonString), t, sizeof(t)/sizeof(t[0])); | ||
CHECK_EQUAL_C_INT(3, jsmnReturn); | ||
|
||
rc = parseStringValue(parsedString, STRING_BUFFER_LENGTH, pJsonString, t + 2); | ||
|
||
CHECK_EQUAL_C_INT(SHADOW_JSON_ERROR, rc); | ||
|
||
/* Ensure there was no attempt to write to a buffer that's too small. */ | ||
for(i = 0; i < STRING_BUFFER_LENGTH; i++) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NP: You could do a mem compare There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't that require keeping an additional block of all-zero memory around? |
||
{ | ||
CHECK_EQUAL_C_CHAR(0, parsedString[i]); | ||
} | ||
} | ||
|
||
TEST_C(JsonUtils, ParseStringEmptyStringIsValid) { int r; | ||
const char *json = "{\"x\":\"\"}"; | ||
char parsedString[50]; | ||
char parsedString[STRING_BUFFER_LENGTH]; | ||
|
||
IOT_DEBUG("\n-->Running Json Utils Tests - Parse empty string \n"); | ||
|
||
r = jsmn_parse(&test_parser, json, strlen(json), t, sizeof(t) / sizeof(t[0])); | ||
rc = parseStringValue(parsedString, json, t + 2); | ||
rc = parseStringValue(parsedString, STRING_BUFFER_LENGTH, json, t + 2); | ||
|
||
CHECK_EQUAL_C_INT(3, r); | ||
CHECK_EQUAL_C_INT(SUCCESS, rc); | ||
|
@@ -87,12 +111,12 @@ TEST_C(JsonUtils, ParseStringEmptyStringIsValid) { int r; | |
TEST_C(JsonUtils, ParseStringErrorOnInteger) { | ||
int r; | ||
const char *json = "{\"x\":3}"; | ||
char parsedString[50]; | ||
char parsedString[STRING_BUFFER_LENGTH]; | ||
|
||
IOT_DEBUG("\n-->Running Json Utils Tests - parse integer as string returns error \n"); | ||
|
||
r = jsmn_parse(&test_parser, json, strlen(json), t, sizeof(t) / sizeof(t[0])); | ||
rc = parseStringValue(parsedString, json, t + 2); | ||
rc = parseStringValue(parsedString, STRING_BUFFER_LENGTH, json, t + 2); | ||
|
||
CHECK_EQUAL_C_INT(3, r); | ||
CHECK_EQUAL_C_INT(JSON_PARSE_ERROR, rc); | ||
|
@@ -101,12 +125,12 @@ TEST_C(JsonUtils, ParseStringErrorOnInteger) { | |
TEST_C(JsonUtils, ParseStringErrorOnBoolean) { | ||
int r; | ||
const char *json = "{\"x\":true}"; | ||
char parsedString[50]; | ||
char parsedString[STRING_BUFFER_LENGTH]; | ||
|
||
IOT_DEBUG("\n-->Running Json Utils Tests - parse boolean as string returns error \n"); | ||
|
||
r = jsmn_parse(&test_parser, json, strlen(json), t, sizeof(t) / sizeof(t[0])); | ||
rc = parseStringValue(parsedString, json, t + 2); | ||
rc = parseStringValue(parsedString, STRING_BUFFER_LENGTH, json, t + 2); | ||
|
||
CHECK_EQUAL_C_INT(3, r); | ||
CHECK_EQUAL_C_INT(JSON_PARSE_ERROR, rc); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!