File gdk-pixbuf-bsc1053417-bmp-updates.patch of Package gdk-pixbuf.33887
From bc6bb89a5d3683afd1495f3cde0730bf679c2fed Mon Sep 17 00:00:00 2001
From: Tobias Mueller <muelli@cryptobitch.de>
Date: Mon, 28 Nov 2016 16:18:42 +0100
Subject: [PATCH 1/7] bmp: Error out when bottom-to-top BMP is too high
BMP files with BITMAPV4HEADER can have negative height when the image is
encoded botton-to-top, but when that negative height is INT_MIN, we
cannot represent it as a positive integer (|INT_MIN| = INT_MAX + 1).
Error out in this case.
https://bugzilla.gnome.org/show_bug.cgi?id=775242
---
gdk-pixbuf/io-bmp.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/gdk-pixbuf/io-bmp.c b/gdk-pixbuf/io-bmp.c
index 08e3c768c..b896a0349 100644
--- a/gdk-pixbuf/io-bmp.c
+++ b/gdk-pixbuf/io-bmp.c
@@ -353,6 +353,14 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
/* Negative heights indicates bottom-down pixelorder */
if (State->Header.height < 0) {
+ if (State->Header.height == INT_MIN) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("BMP image has bogus header data"));
+ State->read_state = READ_STATE_ERROR;
+ return FALSE;
+ }
State->Header.height = -State->Header.height;
State->Header.Negative = 1;
}
--
2.14.1
From 41010e949db097f99fc5242492aa7033f7773ddf Mon Sep 17 00:00:00 2001
From: Gokul Krishnan <gk7huki@gmail.com>
Date: Wed, 25 May 2016 22:24:00 +0000
Subject: [PATCH 2/7] bmp: Add support for BMP headers with bitmask
Header size 52 and 56 failed to load before this patch.
https://bugzilla.gnome.org/show_bug.cgi?id=766890
---
gdk-pixbuf/io-bmp.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/gdk-pixbuf/io-bmp.c b/gdk-pixbuf/io-bmp.c
index b896a0349..f78c092b6 100644
--- a/gdk-pixbuf/io-bmp.c
+++ b/gdk-pixbuf/io-bmp.c
@@ -298,6 +298,18 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
State->Header.height = lsb_32 (&BIH[8]);
State->Header.depth = lsb_16 (&BIH[14]);
State->Compressed = lsb_32 (&BIH[16]);
+ } else if (State->Header.size == 56) {
+ /* BMP v3 with RGBA bitmasks */
+ State->Header.width = lsb_32 (&BIH[4]);
+ State->Header.height = lsb_32 (&BIH[8]);
+ State->Header.depth = lsb_16 (&BIH[14]);
+ State->Compressed = lsb_32 (&BIH[16]);
+ } else if (State->Header.size == 52) {
+ /* BMP v3 with RGB bitmasks */
+ State->Header.width = lsb_32 (&BIH[4]);
+ State->Header.height = lsb_32 (&BIH[8]);
+ State->Header.depth = lsb_16 (&BIH[14]);
+ State->Compressed = lsb_32 (&BIH[16]);
} else if (State->Header.size == 40) {
/* BMP v3 */
State->Header.width = lsb_32 (&BIH[4]);
@@ -495,9 +507,10 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
State->BufferSize = State->LineWidth;
}
} else if (State->Compressed == BI_BITFIELDS) {
- if (State->Header.size == 108 || State->Header.size == 124)
+ if (State->Header.size == 52 || State->Header.size == 56 ||
+ State->Header.size == 108 || State->Header.size == 124)
{
- /* v4 and v5 have the bitmasks in the header */
+ /* extended v3, v4 and v5 have the bitmasks in the header */
if (!decode_bitmasks (&BIH[40], State, error)) {
State->read_state = READ_STATE_ERROR;
return FALSE;
@@ -607,8 +620,8 @@ decode_bitmasks (guchar *buf,
find_bits (State->g_mask, &State->g_shift, &State->g_bits);
find_bits (State->b_mask, &State->b_shift, &State->b_bits);
- /* v4 and v5 have an alpha mask */
- if (State->Header.size == 108 || State->Header.size == 124) {
+ /* extended v3, v4 and v5 have an alpha mask */
+ if (State->Header.size == 56 || State->Header.size == 108 || State->Header.size == 124) {
buf += 4;
State->a_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
find_bits (State->a_mask, &State->a_shift, &State->a_bits);
--
2.14.1
From 111dbb30db97e07c8435b58ea15093bea57c9f1c Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Mon, 16 Jan 2017 10:14:49 +0000
Subject: [PATCH 3/7] io-bmp: Add overflow checks to BMP image saver
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Return an error if the image width or height are too big to fit in the
BMP size fields.
This bumps our GLib dependency to 2.48.0, as it uses
g_uint_checked_mul(). If you want to backport this fix, it’s probably
best to use __builtin_umul_overflow() directly (if compiling using GCC
or another compiler which supports it).
Coverity ID: 1388532
https://bugzilla.gnome.org/show_bug.cgi?id=777315
---
gdk-pixbuf/io-bmp.c | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/gdk-pixbuf/io-bmp.c b/gdk-pixbuf/io-bmp.c
index f78c092b6..6460e7f1b 100644
--- a/gdk-pixbuf/io-bmp.c
+++ b/gdk-pixbuf/io-bmp.c
@@ -1327,6 +1327,7 @@ gdk_pixbuf__bmp_image_save_to_callback (GdkPixbufSaveFunc save_func,
GError **error)
{
guint width, height, channel, size, stride, src_stride, x, y;
+ guint bf_size;
guchar BFH_BIH[54], *pixels, *buf, *src, *dst, *dst_line;
gboolean ret;
@@ -1335,14 +1336,33 @@ gdk_pixbuf__bmp_image_save_to_callback (GdkPixbufSaveFunc save_func,
channel = gdk_pixbuf_get_n_channels (pixbuf);
pixels = gdk_pixbuf_get_pixels (pixbuf);
src_stride = gdk_pixbuf_get_rowstride (pixbuf);
- stride = (width * 3 + 3) & ~3;
- size = stride * height;
+
+ /* stride = (width * 3 + 3) & ~3 */
+ if (!g_uint_checked_mul (&stride, width, 3) ||
+ !g_uint_checked_add (&stride, stride, 3)) {
+ g_set_error_literal (error, GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Image is too wide for BMP format."));
+ return FALSE;
+ }
+
+ stride &= ~3;
+
+ /* size = stride * height
+ * bf_size = size + 14 + 40 */
+ if (!g_uint_checked_mul (&size, stride, height) ||
+ !g_uint_checked_add (&bf_size, size, 14 + 40)) {
+ g_set_error_literal (error, GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Image is too wide for BMP format."));
+ return FALSE;
+ }
/* filling BFH */
dst = BFH_BIH;
*dst++ = 'B'; /* bfType */
*dst++ = 'M';
- put32 (dst, size + 14 + 40); /* bfSize */
+ put32 (dst, bf_size); /* bfSize */
put32 (dst, 0); /* bfReserved1 + bfReserved2 */
put32 (dst, 14 + 40); /* bfOffBits */
--
2.14.1
From ff61b892e87e77ad339c09978d792bd713f4ac3b Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Thu, 13 Jul 2017 18:53:26 +0200
Subject: [PATCH 4/7] loaders: Remove "error && *error == NULL" checks
g_set_error() and friends already do those checks.
---
gdk-pixbuf/io-bmp.c | 10 ++++------
gdk-pixbuf/io-jpeg.c | 26 +++++++++++---------------
gdk-pixbuf/io-png.c | 51 ++++++++++++++++++++-------------------------------
3 files changed, 35 insertions(+), 52 deletions(-)
diff --git a/gdk-pixbuf/io-bmp.c b/gdk-pixbuf/io-bmp.c
index 6460e7f1b..9ba359750 100644
--- a/gdk-pixbuf/io-bmp.c
+++ b/gdk-pixbuf/io-bmp.c
@@ -746,12 +746,10 @@ static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error)
g_object_unref(context->pixbuf);
if (context->read_state == READ_STATE_HEADERS) {
- if (error && *error == NULL) {
- g_set_error_literal (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("Premature end-of-file encountered"));
- }
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Premature end-of-file encountered"));
retval = FALSE;
}
diff --git a/gdk-pixbuf/io-jpeg.c b/gdk-pixbuf/io-jpeg.c
index ee5d321ae..c88ac462d 100644
--- a/gdk-pixbuf/io-jpeg.c
+++ b/gdk-pixbuf/io-jpeg.c
@@ -662,14 +662,12 @@ gdk_pixbuf__jpeg_image_load (FILE *f, GError **error)
default:
g_object_unref (pixbuf);
pixbuf = NULL;
- if (error && *error == NULL) {
- g_set_error (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
- _("Unsupported JPEG color space (%s)"),
- colorspace_name (cinfo.out_color_space));
- }
- goto out;
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+ _("Unsupported JPEG color space (%s)"),
+ colorspace_name (cinfo.out_color_space));
+ goto out;
}
}
@@ -875,13 +873,11 @@ gdk_pixbuf__jpeg_image_load_lines (JpegProgContext *context,
convert_cmyk_to_rgb (cinfo, lines);
break;
default:
- if (error && *error == NULL) {
- g_set_error (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
- _("Unsupported JPEG color space (%s)"),
- colorspace_name (cinfo->out_color_space));
- }
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+ _("Unsupported JPEG color space (%s)"),
+ colorspace_name (cinfo->out_color_space));
return FALSE;
}
diff --git a/gdk-pixbuf/io-png.c b/gdk-pixbuf/io-png.c
index e5ab22bcb..9af7a2c7a 100644
--- a/gdk-pixbuf/io-png.c
+++ b/gdk-pixbuf/io-png.c
@@ -313,13 +313,10 @@ gdk_pixbuf__png_image_load (FILE *f, GError **error)
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, ctype & PNG_COLOR_MASK_ALPHA, 8, w, h);
if (!pixbuf) {
- if (error && *error == NULL) {
- g_set_error_literal (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Insufficient memory to load PNG file"));
- }
-
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Insufficient memory to load PNG file"));
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
return NULL;
@@ -525,11 +522,9 @@ gdk_pixbuf__png_image_stop_load (gpointer context, GError **error)
if (lc->pixbuf)
g_object_unref (lc->pixbuf);
else {
- if (error && *error == NULL) {
- g_set_error_literal (error, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("Premature end-of-file encountered"));
- }
+ g_set_error_literal (error, GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Premature end-of-file encountered"));
retval = FALSE;
}
@@ -664,12 +659,10 @@ png_info_callback (png_structp png_read_ptr,
if (w == 0 || h == 0) {
lc->fatal_error_occurred = TRUE;
- if (lc->error && *lc->error == NULL) {
- g_set_error_literal (lc->error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_FAILED,
- _("Transformed PNG has zero width or height."));
- }
+ g_set_error_literal (lc->error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Transformed PNG has zero width or height."));
return;
}
}
@@ -679,13 +672,11 @@ png_info_callback (png_structp png_read_ptr,
if (lc->pixbuf == NULL) {
/* Failed to allocate memory */
lc->fatal_error_occurred = TRUE;
- if (lc->error && *lc->error == NULL) {
- g_set_error (lc->error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Insufficient memory to store a %lu by %lu image; try exiting some applications to reduce memory usage"),
- (gulong) width, (gulong) height);
- }
+ g_set_error (lc->error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Insufficient memory to store a %lu by %lu image; try exiting some applications to reduce memory usage"),
+ (gulong) width, (gulong) height);
return;
}
@@ -755,12 +746,10 @@ png_row_callback (png_structp png_read_ptr,
if (row_num >= lc->pixbuf->height) {
lc->fatal_error_occurred = TRUE;
- if (lc->error && *lc->error == NULL) {
- g_set_error_literal (lc->error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("Fatal error reading PNG image file"));
- }
+ g_set_error_literal (lc->error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Fatal error reading PNG image file"));
return;
}
--
2.14.1
From 43650722f6facc77e59329cf4f9012a4f8f8fab4 Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Thu, 13 Jul 2017 19:41:06 +0200
Subject: [PATCH 5/7] bmp: Prevent multiplication overflow in DecodeHeader
The multiplication can overflow as UBSan complained:
io-bmp.c:475:63: runtime error: signed integer overflow: 524672 * 4096
cannot be represented in type 'int'
Fix this by checking the header dimensions for sanity, and then checking
whether the rowstride * height multiplication does not overflow and fits
within the range.
https://bugzilla.gnome.org/show_bug.cgi?id=776694
---
gdk-pixbuf/io-bmp.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/gdk-pixbuf/io-bmp.c b/gdk-pixbuf/io-bmp.c
index 9ba359750..e8605058a 100644
--- a/gdk-pixbuf/io-bmp.c
+++ b/gdk-pixbuf/io-bmp.c
@@ -432,6 +432,8 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
State->LineWidth = (State->LineWidth / 4) * 4 + 4;
if (State->pixbuf == NULL) {
+ guint64 len;
+
if (State->size_func) {
gint width = State->Header.width;
gint height = State->Header.height;
@@ -444,6 +446,19 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
}
}
+ /* rowstride is always >= width, so do an early check for bogus header */
+ if (State->Header.width <= 0 ||
+ State->Header.height <= 0 ||
+ !g_uint64_checked_mul (&len, State->Header.width, State->Header.height) ||
+ len > G_MAXINT) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("BMP image has bogus header data"));
+ State->read_state = READ_STATE_ERROR;
+ return FALSE;
+ }
+
if (State->Type == 32 ||
State->Compressed == BI_RLE4 ||
State->Compressed == BI_RLE8)
@@ -456,7 +471,17 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
(gint) State->Header.width,
(gint) State->Header.height);
-
+
+ if (!g_uint64_checked_mul (&len, State->pixbuf->rowstride, State->Header.height) ||
+ len > G_MAXINT) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("BMP image has bogus header data"));
+ State->read_state = READ_STATE_ERROR;
+ return FALSE;
+ }
+
if (State->pixbuf == NULL) {
g_set_error_literal (error,
GDK_PIXBUF_ERROR,
--
2.14.1
From 2cf6b3f01d12618679dab62b58f0bb86d08d74c5 Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Wed, 26 Jul 2017 16:33:40 +0200
Subject: [PATCH 6/7] bmp: Tighten image dimension checks
The rowstride *could* be negative if the pixbuf is invalid. Check that
it is valid before using it to sanity check the image's dimensions.
See https://bugzilla.gnome.org/show_bug.cgi?id=776694
---
gdk-pixbuf/io-bmp.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/gdk-pixbuf/io-bmp.c b/gdk-pixbuf/io-bmp.c
index e8605058a..e8ccce446 100644
--- a/gdk-pixbuf/io-bmp.c
+++ b/gdk-pixbuf/io-bmp.c
@@ -433,6 +433,7 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
if (State->pixbuf == NULL) {
guint64 len;
+ int rowstride;
if (State->size_func) {
gint width = State->Header.width;
@@ -472,7 +473,9 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
(gint) State->Header.width,
(gint) State->Header.height);
- if (!g_uint64_checked_mul (&len, State->pixbuf->rowstride, State->Header.height) ||
+ rowstride = gdk_pixbuf_get_rowstride (State->pixbuf);
+ if (rowstride <= 0 ||
+ !g_uint64_checked_mul (&len, rowstride, State->Header.height) ||
len > G_MAXINT) {
g_set_error_literal (error,
GDK_PIXBUF_ERROR,
--
2.14.1
From b5f42b3f3b41a0a57974345b8780a339d012cb47 Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Wed, 26 Jul 2017 17:07:08 +0200
Subject: [PATCH 7/7] bmp: Avoid allocating large buffers when not needed
Avoid allocating nearly 6 gigs of data when parsing the CVE-2015-4491
test only to free it when we've calculated that the rowstride * height
would overflow by calculating the rowstride before doing the allocation,
using the new gdk_pixbuf_calculate_rowstride() helper.
https://bugzilla.gnome.org/show_bug.cgi?id=765094
---
gdk-pixbuf/io-bmp.c | 28 +++++++++++++++-------------
1 file changed, 15 insertions(+), 13 deletions(-)
diff --git a/gdk-pixbuf/io-bmp.c b/gdk-pixbuf/io-bmp.c
index e8ccce446..06b0cff2c 100644
--- a/gdk-pixbuf/io-bmp.c
+++ b/gdk-pixbuf/io-bmp.c
@@ -434,6 +434,7 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
if (State->pixbuf == NULL) {
guint64 len;
int rowstride;
+ gboolean has_alpha;
if (State->size_func) {
gint width = State->Header.width;
@@ -460,20 +461,17 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
return FALSE;
}
- if (State->Type == 32 ||
- State->Compressed == BI_RLE4 ||
+ if (State->Type == 32 ||
+ State->Compressed == BI_RLE4 ||
State->Compressed == BI_RLE8)
- State->pixbuf =
- gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
- (gint) State->Header.width,
- (gint) State->Header.height);
+ has_alpha = TRUE;
else
- State->pixbuf =
- gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
- (gint) State->Header.width,
- (gint) State->Header.height);
+ has_alpha = FALSE;
+
+ rowstride = gdk_pixbuf_calculate_rowstride (GDK_COLORSPACE_RGB, has_alpha, 8,
+ (gint) State->Header.width,
+ (gint) State->Header.height);
- rowstride = gdk_pixbuf_get_rowstride (State->pixbuf);
if (rowstride <= 0 ||
!g_uint64_checked_mul (&len, rowstride, State->Header.height) ||
len > G_MAXINT) {
@@ -485,6 +483,10 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
return FALSE;
}
+ State->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, has_alpha, 8,
+ (gint) State->Header.width,
+ (gint) State->Header.height);
+
if (State->pixbuf == NULL) {
g_set_error_literal (error,
GDK_PIXBUF_ERROR,
@@ -492,8 +494,8 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
_("Not enough memory to load bitmap image"));
State->read_state = READ_STATE_ERROR;
return FALSE;
- }
-
+ }
+
if (State->prepared_func != NULL)
/* Notify the client that we are ready to go */
(*State->prepared_func) (State->pixbuf, NULL, State->user_data);
--
2.14.1