[libgdata] core: Fix a data corruption bug in GDataBuffer



commit 3809b38e6651ab6b533feea9cff0b95a0ccede95
Author: Philip Withnall <philip tecnocode co uk>
Date:   Sat Aug 9 17:51:42 2014 +0100

    core: Fix a data corruption bug in GDataBuffer
    
    In some situations, the buffer was reading off the end of a chunk and
    into undefined memory. Spotted by asan.
    
    e.g. Take a GDataBuffer with two chunks:
     • Chunk 1, length 8192
     • Chunk 2, length 699
    and with head_read_offset = 8187 from a previous read. There are thus
    704 bytes unread in the buffer.
    
    If a read of 8192 bytes is performed, 5 bytes should come from chunk 1
    and the remaining 699 from chunk 2. length_remaining was being
    (correctly) set to 704, but then the while loop was not being entered,
    as 704 is not greater than or equal to 8192 (the length of chunk 1). The
    code was then falling into the G_LIKELY case below, and attempting to
    read 704 bytes from offset 8187 of chunk 1 — overreading by 699 bytes
    off the end of the chunk, and never getting the 699 bytes from chunk 2.
    
    This can be fixed by correctly taking the head_read_offset into account
    for the while condition.

 gdata/gdata-buffer.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
---
diff --git a/gdata/gdata-buffer.c b/gdata/gdata-buffer.c
index 7b5c2fc..e7b4699 100644
--- a/gdata/gdata-buffer.c
+++ b/gdata/gdata-buffer.c
@@ -268,7 +268,7 @@ gdata_buffer_pop_data (GDataBuffer *self, guint8 *data, gsize length_requested,
 
        /* We can't assume we'll have enough data, since we may have reached EOF */
        chunk = self->head;
-       while (chunk != NULL && length_remaining >= chunk->length) {
+       while (chunk != NULL && self->head_read_offset + length_remaining >= chunk->length) {
                GDataBufferChunk *next_chunk;
                gsize chunk_length = chunk->length - self->head_read_offset;
 
@@ -292,6 +292,7 @@ gdata_buffer_pop_data (GDataBuffer *self, guint8 *data, gsize length_requested,
         * been corrupted somewhere). */
        if (G_LIKELY (length_remaining > 0)) {
                g_assert (chunk != NULL);
+               g_assert_cmpuint (length_remaining, <=, chunk->length);
 
                /* Copy the requested data to the output */
                if (data != NULL) {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]