You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-07-17 01:12:23 +02:00
Harden IO filters against zero input and optimize zero output case.
Add production checks to ensure no filter gets a zero-size input buffer. Also, optimize the case where a filter returns no output. There's no sense in running downstream filters if they have no new input.
This commit is contained in:
@ -36,6 +36,10 @@
|
|||||||
</release-bug-list>
|
</release-bug-list>
|
||||||
|
|
||||||
<release-development-list>
|
<release-development-list>
|
||||||
|
<release-item>
|
||||||
|
<p>Harden IO filters against zero input and optimize zero output case.</p>
|
||||||
|
</release-item>
|
||||||
|
|
||||||
<release-item>
|
<release-item>
|
||||||
<p>Move <code>lockRelease()</code> to the end of <code>exitSafe()</code>.</p>
|
<p>Move <code>lockRelease()</code> to the end of <code>exitSafe()</code>.</p>
|
||||||
</release-item>
|
</release-item>
|
||||||
|
@ -64,6 +64,7 @@ ioFilterProcessIn(IoFilter *this, const Buffer *input)
|
|||||||
|
|
||||||
ASSERT(this != NULL);
|
ASSERT(this != NULL);
|
||||||
ASSERT(this->interface.in != NULL);
|
ASSERT(this->interface.in != NULL);
|
||||||
|
CHECK(input != NULL && bufUsed(input) > 0);
|
||||||
|
|
||||||
this->interface.in(this->driver, input);
|
this->interface.in(this->driver, input);
|
||||||
|
|
||||||
@ -85,9 +86,11 @@ ioFilterProcessInOut(IoFilter *this, const Buffer *input, Buffer *output)
|
|||||||
ASSERT(this != NULL);
|
ASSERT(this != NULL);
|
||||||
ASSERT(output != NULL);
|
ASSERT(output != NULL);
|
||||||
ASSERT(this->interface.inOut != NULL);
|
ASSERT(this->interface.inOut != NULL);
|
||||||
|
CHECK(input == NULL || bufUsed(input) > 0);
|
||||||
|
|
||||||
this->interface.inOut(this->driver, input, output);
|
this->interface.inOut(this->driver, input, output);
|
||||||
|
|
||||||
|
CHECK(!ioFilterInputSame(this) || bufUsed(output) > 0);
|
||||||
FUNCTION_TEST_RETURN_VOID();
|
FUNCTION_TEST_RETURN_VOID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,13 +269,19 @@ ioFilterGroupProcess(IoFilterGroup *this, const Buffer *input, Buffer *output)
|
|||||||
|
|
||||||
ioFilterProcessInOut(filterData->filter, filterData->input, filterData->output);
|
ioFilterProcessInOut(filterData->filter, filterData->input, filterData->output);
|
||||||
|
|
||||||
// If inputSame is set then the output buffer for this filter is full and it will need to be pre-processed with
|
// If there was no output then break out of filter processing because more input is needed
|
||||||
// the same input once the output buffer is cleared.
|
if (bufUsed(filterData->output) == 0)
|
||||||
if (ioFilterInputSame(filterData->filter))
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Else if inputSame is set then the output buffer for this filter is full and it will need to be re-processed
|
||||||
|
// with the same input once the output buffer is cleared
|
||||||
|
else if (ioFilterInputSame(filterData->filter))
|
||||||
|
{
|
||||||
this->inputSame = true;
|
this->inputSame = true;
|
||||||
|
}
|
||||||
// Else clear the buffer if it was locally allocated. If this is an input buffer that was passed in then the
|
// Else clear the buffer if it was locally allocated. If the input buffer was passed in then the caller is
|
||||||
// caller is responsible for clearing it.
|
// responsible for clearing it.
|
||||||
else if (filterData->inputLocal != NULL)
|
else if (filterData->inputLocal != NULL)
|
||||||
bufUsedZero(filterData->inputLocal);
|
bufUsedZero(filterData->inputLocal);
|
||||||
}
|
}
|
||||||
|
@ -270,7 +270,6 @@ testRun(void)
|
|||||||
|
|
||||||
bufUsedZero(decryptBuffer);
|
bufUsedZero(decryptBuffer);
|
||||||
|
|
||||||
ioFilterProcessInOut(blockDecryptFilter, bufNew(0), decryptBuffer);
|
|
||||||
TEST_ERROR(ioFilterProcessInOut(blockDecryptFilter, NULL, decryptBuffer), CryptoError, "cipher header missing");
|
TEST_ERROR(ioFilterProcessInOut(blockDecryptFilter, NULL, decryptBuffer), CryptoError, "cipher header missing");
|
||||||
|
|
||||||
cipherBlockFree(blockDecrypt);
|
cipherBlockFree(blockDecrypt);
|
||||||
|
@ -122,6 +122,7 @@ typedef struct IoTestFilterMultiply
|
|||||||
{
|
{
|
||||||
MemContext *memContext;
|
MemContext *memContext;
|
||||||
unsigned int flushTotal;
|
unsigned int flushTotal;
|
||||||
|
bool writeZero;
|
||||||
char flushChar;
|
char flushChar;
|
||||||
Buffer *multiplyBuffer;
|
Buffer *multiplyBuffer;
|
||||||
unsigned int multiplier;
|
unsigned int multiplier;
|
||||||
@ -143,9 +144,17 @@ ioTestFilterMultiplyProcess(IoTestFilterMultiply *this, const Buffer *input, Buf
|
|||||||
|
|
||||||
if (input == NULL)
|
if (input == NULL)
|
||||||
{
|
{
|
||||||
char flushZ[] = {this->flushChar, 0};
|
// Write nothing into the output buffer to make sure the filter processing will skip the remaining filters
|
||||||
bufCat(output, bufNewC(1, flushZ));
|
if (!this->writeZero)
|
||||||
this->flushTotal--;
|
{
|
||||||
|
this->writeZero = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char flushZ[] = {this->flushChar, 0};
|
||||||
|
bufCat(output, bufNewC(1, flushZ));
|
||||||
|
this->flushTotal--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user