[Spice-devel] [PATCH v2 3/8] replay: Handle errors reading strings from record file

Frediano Ziglio fziglio at redhat.com
Thu Sep 15 22:19:35 UTC 2016


To check fscanf read all needed information a dummy "%n" is appended
to any string and the value stored there is tested. This as scanf family
could return a valid value but not entirely process the string so
adding a "%n" and checking this was processed make sure all expected
string is found.
The code to check for a specific string is now a bit more complicated
as replay_fscanf use a macro which append a constant string.
The "error" field is used to mark any error happened, so in most cases
there is no explicit check beside when this could cause a problem
(for instance results of replay_fscanf used which would result in
uninitialised variable usage).

Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
---
 server/red-replay-qxl.c | 91 +++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 80 insertions(+), 11 deletions(-)

diff --git a/server/red-replay-qxl.c b/server/red-replay-qxl.c
index 518d5bc..dbaa995 100644
--- a/server/red-replay-qxl.c
+++ b/server/red-replay-qxl.c
@@ -49,6 +49,7 @@ struct SpiceReplay {
     GArray *id_map_inv; // replay id -> record id
     GArray *id_free; // free list
     int nsurfaces;
+    int end_pos;
 
     GList *allocated;
 
@@ -69,11 +70,13 @@ static int replay_fread(SpiceReplay *replay, uint8_t *buf, size_t size)
 }
 
 __attribute__((format(scanf, 2, 3)))
-static replay_t replay_fscanf(SpiceReplay *replay, const char *fmt, ...)
+static replay_t replay_fscanf_check(SpiceReplay *replay, const char *fmt, ...)
 {
     va_list ap;
     int ret;
 
+    replay->end_pos = -1;
+
     if (replay->error) {
         return REPLAY_ERROR;
     }
@@ -84,11 +87,13 @@ static replay_t replay_fscanf(SpiceReplay *replay, const char *fmt, ...)
     va_start(ap, fmt);
     ret = vfscanf(replay->fd, fmt, ap);
     va_end(ap);
-    if (ret == EOF) {
+    if (ret == EOF || replay->end_pos < 0) {
         replay->error = TRUE;
     }
     return replay->error ? REPLAY_ERROR : REPLAY_OK;
 }
+#define replay_fscanf(r, fmt, ...) \
+    replay_fscanf_check(r, fmt "%n", ## __VA_ARGS__, &r->end_pos)
 
 static inline void *replay_malloc(SpiceReplay *replay, size_t size)
 {
@@ -210,9 +215,11 @@ static replay_t read_binary(SpiceReplay *replay, const char *prefix, size_t *siz
     uint8_t *zlib_buffer;
     z_stream strm;
 
-    snprintf(template, sizeof(template), "binary %%d %s %%ld:", prefix);
-    if (replay_fscanf(replay, template, &with_zlib, size) == REPLAY_ERROR)
+    snprintf(template, sizeof(template), "binary %%d %s %%ld:%%n", prefix);
+    replay_fscanf_check(replay, template, &with_zlib, size, &replay->end_pos);
+    if (replay->error) {
         return REPLAY_ERROR;
+    }
 
     if (*buf == NULL) {
         *buf = replay_malloc(replay, *size + base_size);
@@ -224,15 +231,19 @@ static replay_t read_binary(SpiceReplay *replay, const char *prefix, size_t *siz
         hexdump(*buf + base_size, *size);
     }
 #else
-    spice_return_val_if_fail(with_zlib != -1, REPLAY_ERROR);
     if (with_zlib) {
         int ret;
         GList *elem;
 
         replay_fscanf(replay, "%d:", &zlib_size);
+        if (replay->error) {
+            return REPLAY_ERROR;
+        }
         zlib_buffer = replay_malloc(replay, zlib_size);
         elem = replay->allocated;
-        replay_fread(replay, zlib_buffer, zlib_size);
+        if (replay_fread(replay, zlib_buffer, zlib_size) != zlib_size) {
+            return REPLAY_ERROR;
+        }
         strm.zalloc = Z_NULL;
         strm.zfree = Z_NULL;
         strm.opaque = Z_NULL;
@@ -265,8 +276,7 @@ static replay_t read_binary(SpiceReplay *replay, const char *prefix, size_t *siz
         replay_fread(replay, *buf + base_size, *size);
     }
 #endif
-    replay_fscanf(replay, "\n");
-    return REPLAY_OK;
+    return replay_fscanf(replay, "\n");
 }
 
 static size_t red_replay_data_chunks(SpiceReplay *replay, const char *prefix,
@@ -337,8 +347,9 @@ static void red_replay_rect_ptr(SpiceReplay *replay, const char *prefix, QXLRect
 {
     char template[1024];
 
-    snprintf(template, sizeof(template), "rect %s %%d %%d %%d %%d\n", prefix);
-    replay_fscanf(replay, template, &qxl->top, &qxl->left, &qxl->bottom, &qxl->right);
+    snprintf(template, sizeof(template), "rect %s %%d %%d %%d %%d\n%%n", prefix);
+    replay_fscanf_check(replay, template, &qxl->top, &qxl->left, &qxl->bottom, &qxl->right,
+                        &replay->end_pos);
 }
 
 static QXLPath *red_replay_path(SpiceReplay *replay)
@@ -364,6 +375,9 @@ static QXLClipRects *red_replay_clip_rects(SpiceReplay *replay)
     int num_rects;
 
     replay_fscanf(replay, "num_rects %d\n", &num_rects);
+    if (replay->error) {
+        return NULL;
+    }
     red_replay_data_chunks(replay, "clip_rects", (uint8_t**)&qxl, sizeof(QXLClipRects));
     qxl->num_rects = num_rects;
     return qxl;
@@ -392,6 +406,9 @@ static QXLImage *red_replay_image(SpiceReplay *replay, uint32_t flags)
     int has_image;
 
     replay_fscanf(replay, "image %d\n", &has_image);
+    if (replay->error) {
+        return NULL;
+    }
     if (!has_image) {
         return NULL;
     }
@@ -402,6 +419,9 @@ static QXLImage *red_replay_image(SpiceReplay *replay, uint32_t flags)
     replay_fscanf(replay, "descriptor.flags %d\n", &temp); qxl->descriptor.flags = temp;
     replay_fscanf(replay, "descriptor.width %d\n", &qxl->descriptor.width);
     replay_fscanf(replay, "descriptor.height %d\n", &qxl->descriptor.height);
+    if (replay->error) {
+        return NULL;
+    }
 
     switch (qxl->descriptor.type) {
     case SPICE_IMAGE_TYPE_BITMAP:
@@ -417,6 +437,9 @@ static QXLImage *red_replay_image(SpiceReplay *replay, uint32_t flags)
             int i, num_ents;
 
             replay_fscanf(replay, "qp.num_ents %d\n", &num_ents);
+            if (replay->error) {
+                return NULL;
+            }
             qp = replay_malloc(replay, sizeof(QXLPalette) + num_ents * sizeof(qp->ents[0]));
             qp->num_ents = num_ents;
             qxl->bitmap.palette = QXLPHYSICAL_FROM_PTR(qp);
@@ -441,12 +464,18 @@ static QXLImage *red_replay_image(SpiceReplay *replay, uint32_t flags)
         break;
     case SPICE_IMAGE_TYPE_SURFACE:
         replay_fscanf(replay, "surface_image.surface_id %d\n", &qxl->surface_image.surface_id);
+        if (replay->error) {
+            return NULL;
+        }
         qxl->surface_image.surface_id = replay_id_get(replay, qxl->surface_image.surface_id);
         break;
     case SPICE_IMAGE_TYPE_QUIC:
         // TODO - make this much nicer (precompute size and allocs, store them during
         // record, then reread into them. and use MPEG-4).
         replay_fscanf(replay, "quic.data_size %d\n", &qxl->quic.data_size);
+        if (replay->error) {
+            return NULL;
+        }
         qxl = realloc(qxl, sizeof(QXLImageDescriptor) + sizeof(QXLQUICData) +
                       qxl->quic.data_size);
         size = red_replay_data_chunks(replay, "quic.data", (uint8_t**)&qxl->quic.data, 0);
@@ -488,6 +517,10 @@ static void red_replay_image_free(SpiceReplay *replay, QXLPHYSICAL p, uint32_t f
 static void red_replay_brush_ptr(SpiceReplay *replay, QXLBrush *qxl, uint32_t flags)
 {
     replay_fscanf(replay, "type %d\n", &qxl->type);
+    if (replay->error) {
+        return;
+    }
+
     switch (qxl->type) {
     case SPICE_BRUSH_TYPE_SOLID:
         replay_fscanf(replay, "u.color %d\n", &qxl->u.color);
@@ -652,6 +685,9 @@ static void red_replay_stroke_ptr(SpiceReplay *replay, QXLStroke *qxl, uint32_t
 
     qxl->path = QXLPHYSICAL_FROM_PTR(red_replay_path(replay));
     replay_fscanf(replay, "attr.flags %d\n", &temp); qxl->attr.flags = temp;
+    if (replay->error) {
+        return;
+    }
     if (qxl->attr.flags & SPICE_LINE_FLAGS_STYLED) {
         size_t size;
 
@@ -749,6 +785,9 @@ static void red_replay_invers_free(SpiceReplay *replay, QXLInvers *qxl, uint32_t
 static void red_replay_clip_ptr(SpiceReplay *replay, QXLClip *qxl)
 {
     replay_fscanf(replay, "type %d\n", &qxl->type);
+    if (replay->error) {
+        return;
+    }
     switch (qxl->type) {
     case SPICE_CLIP_TYPE_RECTS:
         qxl->data = QXLPHYSICAL_FROM_PTR(red_replay_clip_rects(replay));
@@ -778,7 +817,7 @@ static uint8_t *red_replay_transform(SpiceReplay *replay)
 
 static void red_replay_composite_ptr(SpiceReplay *replay, QXLComposite *qxl, uint32_t flags)
 {
-    int enabled;
+    int enabled = 0;
 
     replay_fscanf(replay, "flags %d\n", &qxl->flags);
     qxl->src = QXLPHYSICAL_FROM_PTR(red_replay_image(replay, flags));
@@ -818,15 +857,24 @@ static QXLDrawable *red_replay_native_drawable(SpiceReplay *replay, uint32_t fla
     replay_fscanf(replay, "self_bitmap %d\n", &temp); qxl->self_bitmap = temp;
     red_replay_rect_ptr(replay, "self_bitmap_area", &qxl->self_bitmap_area);
     replay_fscanf(replay, "surface_id %d\n", &qxl->surface_id);
+    if (replay->error) {
+        return NULL;
+    }
     qxl->surface_id = replay_id_get(replay, qxl->surface_id);
 
     for (i = 0; i < 3; i++) {
         replay_fscanf(replay, "surfaces_dest %d\n", &qxl->surfaces_dest[i]);
+        if (replay->error) {
+            return NULL;
+        }
         qxl->surfaces_dest[i] = replay_id_get(replay, qxl->surfaces_dest[i]);
         red_replay_rect_ptr(replay, "surfaces_rects", &qxl->surfaces_rects[i]);
     }
 
     replay_fscanf(replay, "type %d\n", &temp); qxl->type = temp;
+    if (replay->error) {
+        return NULL;
+    }
     switch (qxl->type) {
     case QXL_DRAW_ALPHA_BLEND:
         red_replay_alpha_blend_ptr(replay, &qxl->u.alpha_blend, flags);
@@ -949,6 +997,9 @@ static QXLCompatDrawable *red_replay_compat_drawable(SpiceReplay *replay, uint32
     red_replay_rect_ptr(replay, "bitmap_area", &qxl->bitmap_area);
 
     replay_fscanf(replay, "type %d\n", &temp); qxl->type = temp;
+    if (replay->error) {
+        return NULL;
+    }
     switch (qxl->type) {
     case QXL_DRAW_ALPHA_BLEND:
         red_replay_alpha_blend_ptr_compat(replay, &qxl->u.alpha_blend, flags);
@@ -1019,6 +1070,9 @@ static QXLUpdateCmd *red_replay_update_cmd(SpiceReplay *replay)
     red_replay_rect_ptr(replay, "area", &qxl->area);
     replay_fscanf(replay, "update_id %d\n", &qxl->update_id);
     replay_fscanf(replay, "surface_id %d\n", &qxl->surface_id);
+    if (replay->error) {
+        return NULL;
+    }
     qxl->surface_id = replay_id_get(replay, qxl->surface_id);
 
     return qxl;
@@ -1044,6 +1098,9 @@ static QXLSurfaceCmd *red_replay_surface_cmd(SpiceReplay *replay)
     replay_fscanf(replay, "surface_id %d\n", &qxl->surface_id);
     replay_fscanf(replay, "type %d\n", &temp); qxl->type = temp;
     replay_fscanf(replay, "flags %d\n", &qxl->flags);
+    if (replay->error) {
+        return NULL;
+    }
 
     switch (qxl->type) {
     case QXL_SURFACE_CMD_CREATE:
@@ -1051,6 +1108,9 @@ static QXLSurfaceCmd *red_replay_surface_cmd(SpiceReplay *replay)
         replay_fscanf(replay, "u.surface_create.width %d\n", &qxl->u.surface_create.width);
         replay_fscanf(replay, "u.surface_create.height %d\n", &qxl->u.surface_create.height);
         replay_fscanf(replay, "u.surface_create.stride %d\n", &qxl->u.surface_create.stride);
+        if (replay->error) {
+            return NULL;
+        }
         size = qxl->u.surface_create.height * abs(qxl->u.surface_create.stride);
         if ((qxl->flags & QXL_SURF_FLAG_KEEP_DATA) != 0) {
             read_binary(replay, "data", &read_size, (uint8_t**)&qxl->u.surface_create.data, 0);
@@ -1097,6 +1157,9 @@ static QXLCursor *red_replay_cursor(SpiceReplay *replay)
     cursor.header.hot_spot_y = temp;
 
     replay_fscanf(replay, "data_size %d\n", &temp);
+    if (replay->error) {
+        return NULL;
+    }
     cursor.data_size = temp;
     cursor.data_size = red_replay_data_chunks(replay, "cursor", (uint8_t**)&qxl, sizeof(QXLCursor));
     qxl->header = cursor.header;
@@ -1111,6 +1174,9 @@ static QXLCursorCmd *red_replay_cursor_cmd(SpiceReplay *replay)
 
     replay_fscanf(replay, "cursor_cmd\n");
     replay_fscanf(replay, "type %d\n", &temp);
+    if (replay->error) {
+        return NULL;
+    }
     qxl->type = temp;
     switch (qxl->type) {
     case QXL_CURSOR_SET:
@@ -1160,6 +1226,9 @@ static void replay_handle_create_primary(QXLWorker *worker, SpiceReplay *replay)
         &surface.stride, &surface.format);
     replay_fscanf(replay, "%d %d %d %d\n", &surface.position, &surface.mouse_mode,
         &surface.flags, &surface.type);
+    if (replay->error) {
+        return;
+    }
     read_binary(replay, "data", &size, &mem, 0);
     surface.group_id = 0;
     surface.mem = QXLPHYSICAL_FROM_PTR(mem);
-- 
2.7.4



More information about the Spice-devel mailing list