diff mbox

[4/5] savevm: improve subsections detection on load

Message ID e05dc090635502a743faa3512d08bcc2041841db.1317911543.git.quintela@redhat.com
State New
Headers show

Commit Message

Juan Quintela Oct. 6, 2011, 4:21 p.m. UTC
We add qemu_peek_buffer, that is identical to qemu_get_buffer, just
that it don't update f->buf_index.

We add a paramenter to qemu_peek_byte() to be able to peek more than
one byte.

Once this is done, to see if we have a subsection we look:
- 1st byte is QEMU_VM_SUBSECTION
- 2nd byte is a length, and is bigger than section name
- 3rd element is a string that starts with section_name

So, we shouldn't have false positives (yes, content could still get us
wrong but probabilities are really low).

v2:
- Alex Williamsom found that we could get negative values on index.
- Rework code to fix that part.
- Rewrite qemu_get_buffer() using qemu_peek_buffer()

Signed-off-by: Juan Quintela <quintela@redhat.com>
---
 savevm.c |  110 ++++++++++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 75 insertions(+), 35 deletions(-)

Comments

Paolo Bonzini Oct. 6, 2011, 4:26 p.m. UTC | #1
On 10/06/2011 06:21 PM, Juan Quintela wrote:
> +
> +int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
> +{
> +    int pending = size;
> +    int done = 0;
> +
> +    while (pending>  0) {
> +        int res;
> +
> +        res = qemu_peek_buffer(f, buf, pending, 0);
> +        if (res == 0) {
> +            return 0;
>           }
> -        memcpy(buf, f->buf + f->buf_index, l);
> -        f->buf_index += l;
> -        buf += l;
> -        size -= l;
> +        qemu_file_skip(f, res);
> +        buf += res;
> +        pending -= res;
> +        done += res;
>       }
> -    return size1 - size;
> +    return done;
>   }

This changes semantics for reads above 32KB.  It should be in the commit 
message, or preferably v1 could be committed instead. :)

Paolo
Juan Quintela Oct. 6, 2011, 10:42 p.m. UTC | #2
Paolo Bonzini <pbonzini@redhat.com> wrote:
> On 10/06/2011 06:21 PM, Juan Quintela wrote:
>> +
>> +int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
>> +{
>> +    int pending = size;
>> +    int done = 0;
>> +
>> +    while (pending>  0) {
>> +        int res;
>> +
>> +        res = qemu_peek_buffer(f, buf, pending, 0);
>> +        if (res == 0) {
>> +            return 0;

should this line return "done" insntead?

>>           }
>> -        memcpy(buf, f->buf + f->buf_index, l);
>> -        f->buf_index += l;
>> -        buf += l;
>> -        size -= l;
>> +        qemu_file_skip(f, res);
>> +        buf += res;
>> +        pending -= res;
>> +        done += res;
>>       }
>> -    return size1 - size;
>> +    return done;
>>   }
>
> This changes semantics for reads above 32KB.  It should be in the
> commit message, or preferably v1 could be committed instead. :)

how it changes?  My understanding is that we read the same, only change
that I can think of is the one that I have jsut shown (and that is on
the error case).

Later, Juan.
Paolo Bonzini Oct. 7, 2011, 6:37 a.m. UTC | #3
On 10/07/2011 12:42 AM, Juan Quintela wrote:
>> >  This changes semantics for reads above 32KB.  It should be in the
>> >  commit message, or preferably v1 could be committed instead.:)
> how it changes?  My understanding is that we read the same, only change
> that I can think of is the one that I have jsut shown (and that is on
> the error case).

Yes, you're right.

Paolo
diff mbox

Patch

diff --git a/savevm.c b/savevm.c
index 94628c6..28c0a43 100644
--- a/savevm.c
+++ b/savevm.c
@@ -532,59 +532,85 @@  void qemu_put_byte(QEMUFile *f, int v)
         qemu_fflush(f);
 }

-int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1)
+static void qemu_file_skip(QEMUFile *f, int size)
 {
-    int size, l;
+    if (f->buf_index + size < f->buf_size) {
+        f->buf_index += size;
+    }
+}
+
+static int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
+{
+    int pending;
+    int index;

     if (f->is_write) {
         abort();
     }

-    size = size1;
-    while (size > 0) {
-        l = f->buf_size - f->buf_index;
-        if (l == 0) {
-            qemu_fill_buffer(f);
-            l = f->buf_size - f->buf_index;
-            if (l == 0) {
-                break;
-            }
-        }
-        if (l > size) {
-            l = size;
+    index = f->buf_index + offset;
+    pending = f->buf_size - index;
+    if (pending < size) {
+        qemu_fill_buffer(f);
+        index = f->buf_index + offset;
+        pending = f->buf_size - index;
+    }
+
+    if (pending <= 0) {
+        return 0;
+    }
+    if (size > pending) {
+        size = pending;
+    }
+
+    memcpy(buf, f->buf + index, size);
+    return size;
+}
+
+int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
+{
+    int pending = size;
+    int done = 0;
+
+    while (pending > 0) {
+        int res;
+
+        res = qemu_peek_buffer(f, buf, pending, 0);
+        if (res == 0) {
+            return 0;
         }
-        memcpy(buf, f->buf + f->buf_index, l);
-        f->buf_index += l;
-        buf += l;
-        size -= l;
+        qemu_file_skip(f, res);
+        buf += res;
+        pending -= res;
+        done += res;
     }
-    return size1 - size;
+    return done;
 }

-static int qemu_peek_byte(QEMUFile *f)
+static int qemu_peek_byte(QEMUFile *f, int offset)
 {
+    int index = f->buf_index + offset;
+
     if (f->is_write) {
         abort();
     }

-    if (f->buf_index >= f->buf_size) {
+    if (index >= f->buf_size) {
         qemu_fill_buffer(f);
-        if (f->buf_index >= f->buf_size) {
+        index = f->buf_index + offset;
+        if (index >= f->buf_size) {
             return 0;
         }
     }
-    return f->buf[f->buf_index];
+    return f->buf[index];
 }

 int qemu_get_byte(QEMUFile *f)
 {
     int result;

-    result = qemu_peek_byte(f);
-
-    if (f->buf_index < f->buf_size) {
-        f->buf_index++;
-    }
+    result = qemu_peek_byte(f, 0);
+    qemu_file_skip(f, 1);
     return result;
 }

@@ -1684,22 +1710,36 @@  static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
         return 0;
     }

-    while (qemu_peek_byte(f) == QEMU_VM_SUBSECTION) {
+    while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
         char idstr[256];
         int ret;
-        uint8_t version_id, len;
+        uint8_t version_id, len, size;
         const VMStateDescription *sub_vmsd;

-        qemu_get_byte(f); /* subsection */
-        len = qemu_get_byte(f);
-        qemu_get_buffer(f, (uint8_t *)idstr, len);
-        idstr[len] = 0;
-        version_id = qemu_get_be32(f);
+        len = qemu_peek_byte(f, 1);
+        if (len < strlen(vmsd->name) + 1) {
+            /* subsection name has be be "section_name/a" */
+            return 0;
+        }
+        size = qemu_peek_buffer(f, (uint8_t *)idstr, len, 2);
+        if (size != len) {
+            return 0;
+        }
+        idstr[size] = 0;

+        if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
+            /* it don't have a valid subsection name */
+            return 0;
+        }
         sub_vmsd = vmstate_get_subsection(sub, idstr);
         if (sub_vmsd == NULL) {
             return -ENOENT;
         }
+        qemu_file_skip(f, 1); /* subsection */
+        qemu_file_skip(f, 1); /* len */
+        qemu_file_skip(f, len); /* idstr */
+        version_id = qemu_get_be32(f);
+
         assert(!sub_vmsd->subsections);
         ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
         if (ret) {