mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-03-29 21:47:21 +02:00
Add bufferSize to cvtUInt64FromVarInt128() to further limit reads.
The current call site, manifestFileUnpack(), does not know the total buffer size but the buffer has always been maintained in memory so there should be no corruption. However, there are upcoming use cases where the buffer will be read from IO, the buffer size will be known, and additional sanity checking on buffer overruns will be valuable. Also rename params to align better with cvtUInt64ToVarInt128().
This commit is contained in:
parent
01b81f9d37
commit
ac99201c0e
@ -603,30 +603,35 @@ cvtUInt64ToVarInt128(uint64_t value, uint8_t *const buffer, size_t *const buffer
|
||||
}
|
||||
|
||||
uint64_t
|
||||
cvtUInt64FromVarInt128(const uint8_t *const value, size_t *const valuePos)
|
||||
cvtUInt64FromVarInt128(const uint8_t *const buffer, size_t *const bufferPos, const size_t bufferSize)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM_P(VOID, value);
|
||||
FUNCTION_TEST_PARAM_P(UINT64, valuePos);
|
||||
FUNCTION_TEST_PARAM_P(VOID, buffer);
|
||||
FUNCTION_TEST_PARAM_P(SIZE, bufferPos);
|
||||
FUNCTION_TEST_PARAM(SIZE, bufferSize);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(value != NULL);
|
||||
ASSERT(valuePos != NULL);
|
||||
ASSERT(buffer != NULL);
|
||||
ASSERT(bufferPos != NULL);
|
||||
|
||||
// Decode all bytes
|
||||
uint64_t result = 0;
|
||||
uint8_t byte;
|
||||
|
||||
for (unsigned int valueIdx = 0; valueIdx < CVT_VARINT128_BUFFER_SIZE; valueIdx++)
|
||||
for (unsigned int bufferIdx = 0; bufferIdx < CVT_VARINT128_BUFFER_SIZE; bufferIdx++)
|
||||
{
|
||||
// Error if the buffer position is beyond the buffer size
|
||||
if (*bufferPos >= bufferSize)
|
||||
THROW(FormatError, "buffer position is beyond buffer size");
|
||||
|
||||
// Get the next encoded byte
|
||||
byte = value[*valuePos];
|
||||
byte = buffer[*bufferPos];
|
||||
|
||||
// Shift the lower order 7 encoded bits into the uint64 in reverse order
|
||||
result |= (uint64_t)(byte & 0x7f) << (7 * valueIdx);
|
||||
result |= (uint64_t)(byte & 0x7f) << (7 * bufferIdx);
|
||||
|
||||
// Increment value position to indicate that the byte has been processed
|
||||
(*valuePos)++;
|
||||
// Increment buffer position to indicate that the byte has been processed
|
||||
(*bufferPos)++;
|
||||
|
||||
// Done if the high order bit is not set to indicate more data
|
||||
if (byte < 0x80)
|
||||
@ -634,7 +639,7 @@ cvtUInt64FromVarInt128(const uint8_t *const value, size_t *const valuePos)
|
||||
}
|
||||
|
||||
// By this point all bytes should have been read so error if this is not the case. This could be due to a coding error or
|
||||
// corrupton in the data stream.
|
||||
// corruption in the data stream.
|
||||
if (byte >= 0x80)
|
||||
THROW(FormatError, "unterminated varint-128 integer");
|
||||
|
||||
|
@ -117,7 +117,7 @@ cvtZSubNToUInt64(const char *const value, const size_t offset, const size_t size
|
||||
|
||||
// Convert uint64 to base-128 varint and vice versa
|
||||
void cvtUInt64ToVarInt128(uint64_t value, uint8_t *buffer, size_t *bufferPos, size_t bufferSize);
|
||||
uint64_t cvtUInt64FromVarInt128(const uint8_t *value, size_t *valuePos);
|
||||
uint64_t cvtUInt64FromVarInt128(const uint8_t *buffer, size_t *bufferPos, size_t bufferSize);
|
||||
|
||||
// Convert boolean to zero-terminated string. Use cvtBoolToConstZ() whenever possible since it is more efficient.
|
||||
size_t cvtBoolToZ(bool value, char *buffer, size_t bufferSize);
|
||||
|
@ -246,14 +246,14 @@ manifestFileUnpack(const Manifest *const manifest, const ManifestFilePack *const
|
||||
bufferPos += sizeof(StringPub) + strSize(result.name) + 1;
|
||||
|
||||
// Flags
|
||||
const uint64_t flag = cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos);
|
||||
const uint64_t flag = cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos, UINT_MAX);
|
||||
|
||||
// Size
|
||||
result.size = cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos);
|
||||
result.size = cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos, UINT_MAX);
|
||||
|
||||
// Timestamp
|
||||
result.timestamp =
|
||||
manifestPackBaseTime - (time_t)cvtInt64FromZigZag(cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos));
|
||||
manifestPackBaseTime - (time_t)cvtInt64FromZigZag(cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos, UINT_MAX));
|
||||
|
||||
// Checksum page
|
||||
result.checksumPage = flag & (1 << manifestFilePackFlagChecksumPage) ? true : false;
|
||||
@ -264,33 +264,33 @@ manifestFileUnpack(const Manifest *const manifest, const ManifestFilePack *const
|
||||
|
||||
// Reference
|
||||
if (flag & (1 << manifestFilePackFlagReference))
|
||||
result.reference = (const String *)(uintptr_t)cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos);
|
||||
result.reference = (const String *)(uintptr_t)cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos, UINT_MAX);
|
||||
|
||||
// Mode
|
||||
if (flag & (1 << manifestFilePackFlagMode))
|
||||
result.mode = (mode_t)cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos);
|
||||
result.mode = (mode_t)cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos, UINT_MAX);
|
||||
else
|
||||
result.mode = manifest->fileModeDefault;
|
||||
|
||||
// User/group
|
||||
if (flag & (1 << manifestFilePackFlagUser))
|
||||
result.user = (const String *)(uintptr_t)cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos);
|
||||
result.user = (const String *)(uintptr_t)cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos, UINT_MAX);
|
||||
else if (!(flag & (1 << manifestFilePackFlagUserNull)))
|
||||
result.user = manifest->fileUserDefault;
|
||||
|
||||
if (flag & (1 << manifestFilePackFlagGroup))
|
||||
result.group = (const String *)(uintptr_t)cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos);
|
||||
result.group = (const String *)(uintptr_t)cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos, UINT_MAX);
|
||||
else if (!(flag & (1 << manifestFilePackFlagGroupNull)))
|
||||
result.group = manifest->fileGroupDefault;
|
||||
|
||||
// Repo size
|
||||
result.sizeRepo = cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos);
|
||||
result.sizeRepo = cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos, UINT_MAX);
|
||||
|
||||
// Bundle
|
||||
if (flag & (1 << manifestFilePackFlagBundle))
|
||||
{
|
||||
result.bundleId = cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos);
|
||||
result.bundleOffset = cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos);
|
||||
result.bundleId = cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos, UINT_MAX);
|
||||
result.bundleOffset = cvtUInt64FromVarInt128((const uint8_t *)filePack, &bufferPos, UINT_MAX);
|
||||
}
|
||||
|
||||
// Checksum page error
|
||||
|
@ -224,7 +224,10 @@ testRun(void)
|
||||
TEST_RESULT_UINT(bufferPos, 10, "check buffer position");
|
||||
|
||||
bufferPos = 0;
|
||||
TEST_RESULT_UINT(cvtUInt64FromVarInt128(buffer, &bufferPos), 0xFFFFFFFFFFFFFFFF, "to uint64");
|
||||
TEST_ERROR(cvtUInt64FromVarInt128(buffer, &bufferPos, 1), FormatError, "buffer position is beyond buffer size");
|
||||
|
||||
bufferPos = 0;
|
||||
TEST_RESULT_UINT(cvtUInt64FromVarInt128(buffer, &bufferPos, sizeof(buffer)), 0xFFFFFFFFFFFFFFFF, "to uint64");
|
||||
TEST_RESULT_UINT(bufferPos, 10, "check buffer position");
|
||||
|
||||
bufferPos = 0;
|
||||
@ -232,13 +235,13 @@ testRun(void)
|
||||
TEST_RESULT_UINT(bufferPos, 1, "check buffer position");
|
||||
|
||||
bufferPos = 0;
|
||||
TEST_RESULT_UINT(cvtUInt64FromVarInt128(buffer, &bufferPos), 0, "to uint64");
|
||||
TEST_RESULT_UINT(cvtUInt64FromVarInt128(buffer, &bufferPos, sizeof(buffer)), 0, "to uint64");
|
||||
TEST_RESULT_UINT(bufferPos, 1, "check buffer position");
|
||||
|
||||
uint8_t buffer2[CVT_VARINT128_BUFFER_SIZE + 1];
|
||||
memset(buffer2, 0xFF, sizeof(buffer2));
|
||||
bufferPos = 0;
|
||||
TEST_ERROR(cvtUInt64FromVarInt128(buffer2, &bufferPos), FormatError, "unterminated varint-128 integer");
|
||||
TEST_ERROR(cvtUInt64FromVarInt128(buffer2, &bufferPos, sizeof(buffer)), FormatError, "unterminated varint-128 integer");
|
||||
}
|
||||
|
||||
FUNCTION_HARNESS_RETURN_VOID();
|
||||
|
Loading…
x
Reference in New Issue
Block a user