MXS-870: Handle non-contiguous session command responses
Session command responses with multiple packets could be spread across multiple, non-contiguous buffers. If a buffer contained a complete packet and some extra data but it wasn't contiguous, the debug assertion in gwbuf_clone_portion would fail. With release builds, it would cause eventual out-of-bounds memory access when the response would be sent to the client.
This commit is contained in:
@ -384,7 +384,7 @@ GWBUF* gwbuf_clone_all(GWBUF* buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GWBUF *gwbuf_clone_portion(GWBUF *buf,
|
static GWBUF *gwbuf_clone_portion(GWBUF *buf,
|
||||||
size_t start_offset,
|
size_t start_offset,
|
||||||
size_t length)
|
size_t length)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -375,15 +375,6 @@ test1()
|
|||||||
gwbuf_free(clone);
|
gwbuf_free(clone);
|
||||||
ss_dfprintf(stderr, "Freed cloned buffer");
|
ss_dfprintf(stderr, "Freed cloned buffer");
|
||||||
ss_dfprintf(stderr, "\t..done\n");
|
ss_dfprintf(stderr, "\t..done\n");
|
||||||
partclone = gwbuf_clone_portion(buffer, 25, 50);
|
|
||||||
buflen = GWBUF_LENGTH(partclone);
|
|
||||||
ss_dfprintf(stderr, "Part cloned buffer length is now %d", buflen);
|
|
||||||
ss_info_dassert(50 == buflen, "Incorrect buffer size");
|
|
||||||
ss_info_dassert(0 == GWBUF_EMPTY(partclone), "Part cloned buffer should not be empty");
|
|
||||||
ss_dfprintf(stderr, "\t..done\n");
|
|
||||||
gwbuf_free(partclone);
|
|
||||||
ss_dfprintf(stderr, "Freed part cloned buffer");
|
|
||||||
ss_dfprintf(stderr, "\t..done\n");
|
|
||||||
buffer = gwbuf_consume(buffer, bite1);
|
buffer = gwbuf_consume(buffer, bite1);
|
||||||
ss_info_dassert(NULL != buffer, "Buffer should not be null");
|
ss_info_dassert(NULL != buffer, "Buffer should not be null");
|
||||||
buflen = GWBUF_LENGTH(buffer);
|
buflen = GWBUF_LENGTH(buffer);
|
||||||
|
|||||||
@ -194,7 +194,6 @@ extern unsigned int gwbuf_length(GWBUF *head);
|
|||||||
extern int gwbuf_count(GWBUF *head);
|
extern int gwbuf_count(GWBUF *head);
|
||||||
extern size_t gwbuf_copy_data(GWBUF *buffer, size_t offset, size_t bytes,
|
extern size_t gwbuf_copy_data(GWBUF *buffer, size_t offset, size_t bytes,
|
||||||
uint8_t* dest);
|
uint8_t* dest);
|
||||||
extern GWBUF *gwbuf_clone_portion(GWBUF *head, size_t offset, size_t len);
|
|
||||||
extern GWBUF *gwbuf_split(GWBUF **buf, size_t length);
|
extern GWBUF *gwbuf_split(GWBUF **buf, size_t length);
|
||||||
extern GWBUF *gwbuf_clone_transform(GWBUF *head, gwbuf_type_t type);
|
extern GWBUF *gwbuf_clone_transform(GWBUF *head, gwbuf_type_t type);
|
||||||
extern GWBUF *gwbuf_clone_all(GWBUF* head);
|
extern GWBUF *gwbuf_clone_all(GWBUF* head);
|
||||||
|
|||||||
@ -2012,21 +2012,16 @@ static GWBUF* process_response_data(DCB* dcb,
|
|||||||
readbuf = NULL;
|
readbuf = NULL;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Packet was read. There should be more since bytes were
|
* Buffer contains more data than we need. Split the complete packet and
|
||||||
* left over.
|
* the extra data into two separate buffers.
|
||||||
* Move the next packet to its own buffer and add that next
|
|
||||||
* to the prev packet's buffer.
|
|
||||||
*/
|
*/
|
||||||
else /*< nbytes_left < nbytes_to_process */
|
else
|
||||||
{
|
{
|
||||||
ss_dassert(nbytes_left >= 0);
|
ss_dassert(nbytes_left < nbytes_to_process);
|
||||||
nbytes_to_process -= nbytes_left;
|
ss_dassert(nbytes_left > 0);
|
||||||
|
|
||||||
/** Move the prefix of the buffer to outbuf from redbuf */
|
|
||||||
outbuf = gwbuf_append(outbuf,
|
|
||||||
gwbuf_clone_portion(readbuf, 0, (size_t) nbytes_left));
|
|
||||||
readbuf = gwbuf_consume(readbuf, (size_t) nbytes_left);
|
|
||||||
ss_dassert(npackets_left > 0);
|
ss_dassert(npackets_left > 0);
|
||||||
|
outbuf = gwbuf_append(outbuf, gwbuf_split(&readbuf, nbytes_left));
|
||||||
|
nbytes_to_process -= nbytes_left;
|
||||||
npackets_left -= 1;
|
npackets_left -= 1;
|
||||||
nbytes_left = 0;
|
nbytes_left = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user