Blame SOURCES/0003-lz-More-checks-on-image-sizes.patch

e8160e
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
e8160e
From: Frediano Ziglio <fziglio@redhat.com>
e8160e
Date: Mon, 25 Jun 2018 14:16:10 +0100
e8160e
Subject: [PATCH spice-common 2/2] lz: More checks on image sizes
e8160e
e8160e
Extend sizes check also to decoding, actually the source data
e8160e
decoding images should be less safe than encoding.
e8160e
This avoids different integer overflows and buffer overflows.
e8160e
To avoid potential issues images are limited to 1GB.
e8160e
e8160e
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
e8160e
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
e8160e
---
e8160e
 common/lz.c | 68 ++++++++++++++++++++++++++++++++++++-----------------
e8160e
 1 file changed, 46 insertions(+), 22 deletions(-)
e8160e
e8160e
diff --git a/spice-common/common/lz.c b/spice-common/common/lz.c
e8160e
index 2c5d5e2..167e118 100644
e8160e
--- a/spice-common/common/lz.c
e8160e
+++ b/spice-common/common/lz.c
e8160e
@@ -53,6 +53,8 @@
e8160e
 #define HASH_SIZE (1 << HASH_LOG)
e8160e
 #define HASH_MASK (HASH_SIZE - 1)
e8160e
 
e8160e
+/* Maximum image size, mainly to avoid possible integer overflows */
e8160e
+#define SPICE_MAX_IMAGE_SIZE (1024 * 1024 * 1024 - 1)
e8160e
 
e8160e
 typedef struct LzImageSegment LzImageSegment;
e8160e
 struct LzImageSegment {
e8160e
@@ -481,33 +483,53 @@ typedef uint16_t rgb16_pixel_t;
e8160e
 #undef LZ_UNEXPECT_CONDITIONAL
e8160e
 #undef LZ_EXPECT_CONDITIONAL
e8160e
 
e8160e
-int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_down,
e8160e
-              uint8_t *lines, unsigned int num_lines, int stride,
e8160e
-              uint8_t *io_ptr, unsigned int num_io_bytes)
e8160e
+static void lz_set_sizes(Encoder *encoder, int type, int width, int height, int stride)
e8160e
 {
e8160e
-    Encoder *encoder = (Encoder *)lz;
e8160e
-    uint8_t *io_ptr_end = io_ptr + num_io_bytes;
e8160e
-
e8160e
-    encoder->type = type;
e8160e
-    encoder->width = width;
e8160e
-    encoder->height = height;
e8160e
-    encoder->stride = stride;
e8160e
+    if (width < 0) {
e8160e
+        encoder->usr->error(encoder->usr, "invalid lz width %d\n", width);
e8160e
+    }
e8160e
+    if (height < 0) {
e8160e
+        encoder->usr->error(encoder->usr, "invalid lz height %d\n", height);
e8160e
+    }
e8160e
+    if (stride < 0) {
e8160e
+        encoder->usr->error(encoder->usr, "invalid lz stride %d\n", stride);
e8160e
+    }
e8160e
 
e8160e
-    if (IS_IMAGE_TYPE_PLT[encoder->type]) {
e8160e
-        if (encoder->stride > (width / PLT_PIXELS_PER_BYTE[encoder->type])) {
e8160e
-            if (((width % PLT_PIXELS_PER_BYTE[encoder->type]) == 0) || (
e8160e
-                    (encoder->stride - (width / PLT_PIXELS_PER_BYTE[encoder->type])) > 1)) {
e8160e
+    if (IS_IMAGE_TYPE_PLT[type]) {
e8160e
+        if (stride > (width / PLT_PIXELS_PER_BYTE[type])) {
e8160e
+            if (((width % PLT_PIXELS_PER_BYTE[type]) == 0) || (
e8160e
+                    (stride - (width / PLT_PIXELS_PER_BYTE[type])) > 1)) {
e8160e
                 encoder->usr->error(encoder->usr, "stride overflows (plt)\n");
e8160e
             }
e8160e
         }
e8160e
     } else {
e8160e
-        if (encoder->stride != width * RGB_BYTES_PER_PIXEL[encoder->type]) {
e8160e
+        if (stride != width * RGB_BYTES_PER_PIXEL[type]) {
e8160e
             encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb) %d != %d * %d (%d)\n",
e8160e
-                                encoder->stride, width, RGB_BYTES_PER_PIXEL[encoder->type],
e8160e
-                                encoder->type);
e8160e
+                                stride, width, RGB_BYTES_PER_PIXEL[type],
e8160e
+                                type);
e8160e
         }
e8160e
     }
e8160e
 
e8160e
+    // avoid too big images
e8160e
+    if ((uint64_t) stride * height > SPICE_MAX_IMAGE_SIZE) {
e8160e
+        encoder->usr->error(encoder->usr, "image too large\n");
e8160e
+    }
e8160e
+
e8160e
+    encoder->type = type;
e8160e
+    encoder->width = width;
e8160e
+    encoder->height = height;
e8160e
+    encoder->stride = stride;
e8160e
+}
e8160e
+
e8160e
+int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_down,
e8160e
+              uint8_t *lines, unsigned int num_lines, int stride,
e8160e
+              uint8_t *io_ptr, unsigned int num_io_bytes)
e8160e
+{
e8160e
+    Encoder *encoder = (Encoder *)lz;
e8160e
+    uint8_t *io_ptr_end = io_ptr + num_io_bytes;
e8160e
+
e8160e
+    lz_set_sizes(encoder, type, width, height, stride);
e8160e
+
e8160e
     // assign the output buffer
e8160e
     if (!encoder_reset(encoder, io_ptr, io_ptr_end)) {
e8160e
         encoder->usr->error(encoder->usr, "lz encoder io reset failed\n");
e8160e
@@ -592,13 +614,15 @@ void lz_decode_begin(LzContext *lz, uint8_t *io_ptr, unsigned int num_io_bytes,
e8160e
         encoder->usr->error(encoder->usr, "bad version\n");
e8160e
     }
e8160e
 
e8160e
-    encoder->type = (LzImageType)decode_32(encoder);
e8160e
-    if (encoder->type <= LZ_IMAGE_TYPE_INVALID || encoder->type > LZ_IMAGE_TYPE_A8) {
e8160e
+    int type = decode_32(encoder);
e8160e
+    if (type <= LZ_IMAGE_TYPE_INVALID || type > LZ_IMAGE_TYPE_A8) {
e8160e
         encoder->usr->error(encoder->usr, "invalid lz type %d\n", encoder->type);
e8160e
     }
e8160e
-    encoder->width = decode_32(encoder);
e8160e
-    encoder->height = decode_32(encoder);
e8160e
-    encoder->stride = decode_32(encoder);
e8160e
+    int width = decode_32(encoder);
e8160e
+    int height = decode_32(encoder);
e8160e
+    int stride = decode_32(encoder);
e8160e
+    lz_set_sizes(encoder, type, width, height, stride);
e8160e
+
e8160e
     *out_top_down = decode_32(encoder);
e8160e
 
e8160e
     *out_width = encoder->width;