|
|
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;
|