You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-10-23 21:28:56 +03:00
Fix reads past the end of JSON strings ending in an escape.
jsonReadSkipStr() stepped past the terminating null when a backslash was the last character. It also advanced one character too far after a \uXXXX escape, which skipped the closing quote when the escape was the last character of the string and stepped past the terminating null when the escape was at the end of the input. jsonReadStr() did not check that both digits of a \u00XX escape were present, so a truncated escape at the end of the input was read past the terminating null. The skip path validates the JSON values in info files and manifests. The read path reads object store responses.
This commit is contained in:
@@ -838,11 +838,16 @@ jsonReadSkipStr(JsonRead *const this)
|
||||
if (digitIdx != 4)
|
||||
THROW_FMT(JsonFormatError, "unable to decode at: %s", this->json - 2);
|
||||
|
||||
this->json += 4;
|
||||
// Move to the last digit
|
||||
this->json += 3;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// End of string after the escape
|
||||
case '\0':
|
||||
THROW(JsonFormatError, "expected '\"' but found null delimiter");
|
||||
|
||||
// Any other escape
|
||||
default:
|
||||
break;
|
||||
@@ -1026,8 +1031,11 @@ jsonReadStr(JsonRead *const this)
|
||||
this->json++;
|
||||
|
||||
// We don't know how to decode anything except ASCII so fail if it looks like Unicode
|
||||
if (strncmp(this->json, "00", 2) != 0)
|
||||
if (strncmp(this->json, "00", 2) != 0 || !isxdigit((unsigned char)this->json[2]) ||
|
||||
!isxdigit((unsigned char)this->json[3]))
|
||||
{
|
||||
THROW_FMT(JsonFormatError, "unable to decode at: %s", this->json - 2);
|
||||
}
|
||||
|
||||
// Decode char
|
||||
this->json += 2;
|
||||
|
||||
@@ -60,6 +60,8 @@ testRun(void)
|
||||
TEST_TITLE("error on invalid ascii encoding");
|
||||
|
||||
TEST_ERROR(jsonReadStr(jsonReadNew(STRDEF("\"\\u1111"))), JsonFormatError, "unable to decode at: \\u1111");
|
||||
TEST_ERROR(jsonReadStr(jsonReadNew(STRDEF("\"\\u00x1"))), JsonFormatError, "unable to decode at: \\u00x1");
|
||||
TEST_ERROR(jsonReadStr(jsonReadNew(STRDEF("\"\\u00a"))), JsonFormatError, "unable to decode at: \\u00a");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("error on maximum depth");
|
||||
@@ -229,8 +231,11 @@ testRun(void)
|
||||
TEST_TITLE("validate");
|
||||
|
||||
TEST_RESULT_VOID(jsonValidate(json), "valid");
|
||||
TEST_RESULT_VOID(jsonValidate(STRDEF("[\"\\u0041\",\"\\u1234\"]")), "valid escapes before end of string");
|
||||
TEST_ERROR(jsonValidate(STRDEF("\"\\u0041")), JsonFormatError, "expected '\"' but found null delimiter");
|
||||
TEST_ERROR(jsonValidate(STRDEF("\"\\u000")), JsonFormatError, "unable to decode at: \\u000");
|
||||
TEST_ERROR(jsonValidate(STRDEF("\"")), JsonFormatError, "expected '\"' but found null delimiter");
|
||||
TEST_ERROR(jsonValidate(STRDEF("\"\\")), JsonFormatError, "expected '\"' but found null delimiter");
|
||||
TEST_ERROR(jsonValidate(STRDEF("{\"key\"x")), JsonFormatError, "expected : after key at: x");
|
||||
TEST_ERROR(jsonValidate(strNewFmt("%s]", strZ(json))), JsonFormatError, "characters after JSON at: ]");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user