[Spice-devel] [PATCH v3 2/8] replay: Handle errors reading strings from record file
Frediano Ziglio
fziglio at redhat.com
Fri Sep 16 11:32:55 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 7eddaf4..968a605 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