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:
Markus Makela
2016-09-19 05:34:03 +03:00
parent 7fc7249349
commit 92ef33327e
4 changed files with 12 additions and 27 deletions

View File

@ -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)
{ {

View File

@ -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);

View File

@ -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);

View File

@ -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;
} }