260 lines
13 KiB
Diff
260 lines
13 KiB
Diff
commit f53faac253bbf2f8326a4898c805fb3596694665
|
|
Author: Nils Philippsen <nils@redhat.com>
|
|
Date: Tue Nov 17 11:56:08 2009 +0100
|
|
|
|
patch: psd-hardening
|
|
|
|
Squashed commit of the following:
|
|
|
|
commit de05a3ec3d0a452fb48d4705cec8d4bb505364d2
|
|
Author: Simon Budig <simon@gimp.org>
|
|
Date: Tue Nov 17 00:41:39 2009 +0100
|
|
|
|
Harden the PSD plugin against integer overflows.
|
|
|
|
Issues discovered by Stefan Cornelius, Secunia Research, advisory SA37232
|
|
and CVE identifier CVE-2009-3909. Fixes bug #600741.
|
|
(cherry picked from commit 9cc8d78ff33b7a36852b74e64b427489cad44d0e)
|
|
(cherry picked from commit 88eccea84aa375197cc04a2a0e2e29debb56bfa5)
|
|
|
|
Signed-off-by: Nils Philippsen <nils@redhat.com>
|
|
|
|
commit 35ec53d2a1363380a0c6c3f64280e99d7d07f90a
|
|
Author: Simon Budig <simon@gimp.org>
|
|
Date: Tue Nov 17 01:12:19 2009 +0100
|
|
|
|
Fix the PSD structs to use signed ints for bounding box coordinates.
|
|
(cherry picked from commit 0e440cb6d4d6ee029667363d244aff61b154c33c)
|
|
(cherry picked from commit 687ec47914ec08d6e460918cb641c196d80140a3)
|
|
|
|
Signed-off-by: Nils Philippsen <nils@redhat.com>
|
|
|
|
diff --git a/plug-ins/file-psd/psd-load.c b/plug-ins/file-psd/psd-load.c
|
|
index d0a8455..1b4e944 100644
|
|
--- a/plug-ins/file-psd/psd-load.c
|
|
+++ b/plug-ins/file-psd/psd-load.c
|
|
@@ -304,6 +304,15 @@ read_header_block (PSDimage *img_a,
|
|
return -1;
|
|
}
|
|
|
|
+ /* img_a->rows is sanitized above, so a division by zero is avoided here */
|
|
+ if (img_a->columns > G_MAXINT32 / img_a->rows)
|
|
+ {
|
|
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
+ _("Unsupported or invalid image size: %dx%d"),
|
|
+ img_a->columns, img_a->rows);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
if (img_a->color_mode != PSD_BITMAP
|
|
&& img_a->color_mode != PSD_GRAYSCALE
|
|
&& img_a->color_mode != PSD_INDEXED
|
|
@@ -533,10 +542,10 @@ read_layer_block (PSDimage *img_a,
|
|
psd_set_error (feof (f), errno, error);
|
|
return NULL;
|
|
}
|
|
- lyr_a[lidx]->top = GUINT32_FROM_BE (lyr_a[lidx]->top);
|
|
- lyr_a[lidx]->left = GUINT32_FROM_BE (lyr_a[lidx]->left);
|
|
- lyr_a[lidx]->bottom = GUINT32_FROM_BE (lyr_a[lidx]->bottom);
|
|
- lyr_a[lidx]->right = GUINT32_FROM_BE (lyr_a[lidx]->right);
|
|
+ lyr_a[lidx]->top = GINT32_FROM_BE (lyr_a[lidx]->top);
|
|
+ lyr_a[lidx]->left = GINT32_FROM_BE (lyr_a[lidx]->left);
|
|
+ lyr_a[lidx]->bottom = GINT32_FROM_BE (lyr_a[lidx]->bottom);
|
|
+ lyr_a[lidx]->right = GINT32_FROM_BE (lyr_a[lidx]->right);
|
|
lyr_a[lidx]->num_channels = GUINT16_FROM_BE (lyr_a[lidx]->num_channels);
|
|
|
|
if (lyr_a[lidx]->num_channels > MAX_CHANNELS)
|
|
@@ -546,14 +555,16 @@ read_layer_block (PSDimage *img_a,
|
|
lyr_a[lidx]->num_channels);
|
|
return NULL;
|
|
}
|
|
- if (lyr_a[lidx]->bottom - lyr_a[lidx]->top > GIMP_MAX_IMAGE_SIZE)
|
|
+ if (lyr_a[lidx]->bottom < lyr_a[lidx]->top ||
|
|
+ lyr_a[lidx]->bottom - lyr_a[lidx]->top > GIMP_MAX_IMAGE_SIZE)
|
|
{
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
_("Unsupported or invalid layer height: %d"),
|
|
lyr_a[lidx]->bottom - lyr_a[lidx]->top);
|
|
return NULL;
|
|
}
|
|
- if (lyr_a[lidx]->right - lyr_a[lidx]->left > GIMP_MAX_IMAGE_SIZE)
|
|
+ if (lyr_a[lidx]->right < lyr_a[lidx]->left ||
|
|
+ lyr_a[lidx]->right - lyr_a[lidx]->left > GIMP_MAX_IMAGE_SIZE)
|
|
{
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
_("Unsupported or invalid layer width: %d"),
|
|
@@ -561,6 +572,16 @@ read_layer_block (PSDimage *img_a,
|
|
return NULL;
|
|
}
|
|
|
|
+ if ((lyr_a[lidx]->right - lyr_a[lidx]->left) >
|
|
+ G_MAXINT32 / MAX (lyr_a[lidx]->bottom - lyr_a[lidx]->top, 1))
|
|
+ {
|
|
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
+ _("Unsupported or invalid layer size: %dx%d"),
|
|
+ lyr_a[lidx]->right - lyr_a[lidx]->left,
|
|
+ lyr_a[lidx]->bottom - lyr_a[lidx]->top);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
IFDBG(2) g_debug ("Layer %d, Coords %d %d %d %d, channels %d, ",
|
|
lidx, lyr_a[lidx]->left, lyr_a[lidx]->top,
|
|
lyr_a[lidx]->right, lyr_a[lidx]->bottom,
|
|
@@ -670,13 +691,13 @@ read_layer_block (PSDimage *img_a,
|
|
return NULL;
|
|
}
|
|
lyr_a[lidx]->layer_mask.top =
|
|
- GUINT32_FROM_BE (lyr_a[lidx]->layer_mask.top);
|
|
+ GINT32_FROM_BE (lyr_a[lidx]->layer_mask.top);
|
|
lyr_a[lidx]->layer_mask.left =
|
|
- GUINT32_FROM_BE (lyr_a[lidx]->layer_mask.left);
|
|
+ GINT32_FROM_BE (lyr_a[lidx]->layer_mask.left);
|
|
lyr_a[lidx]->layer_mask.bottom =
|
|
- GUINT32_FROM_BE (lyr_a[lidx]->layer_mask.bottom);
|
|
+ GINT32_FROM_BE (lyr_a[lidx]->layer_mask.bottom);
|
|
lyr_a[lidx]->layer_mask.right =
|
|
- GUINT32_FROM_BE (lyr_a[lidx]->layer_mask.right);
|
|
+ GINT32_FROM_BE (lyr_a[lidx]->layer_mask.right);
|
|
lyr_a[lidx]->layer_mask.mask_flags.relative_pos =
|
|
lyr_a[lidx]->layer_mask.flags & 1 ? TRUE : FALSE;
|
|
lyr_a[lidx]->layer_mask.mask_flags.disabled =
|
|
@@ -702,21 +723,21 @@ read_layer_block (PSDimage *img_a,
|
|
return NULL;
|
|
}
|
|
lyr_a[lidx]->layer_mask_extra.top =
|
|
- GUINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.top);
|
|
+ GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.top);
|
|
lyr_a[lidx]->layer_mask_extra.left =
|
|
- GUINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.left);
|
|
+ GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.left);
|
|
lyr_a[lidx]->layer_mask_extra.bottom =
|
|
- GUINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.bottom);
|
|
+ GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.bottom);
|
|
lyr_a[lidx]->layer_mask_extra.right =
|
|
- GUINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.right);
|
|
+ GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.right);
|
|
lyr_a[lidx]->layer_mask.top =
|
|
- GUINT32_FROM_BE (lyr_a[lidx]->layer_mask.top);
|
|
+ GINT32_FROM_BE (lyr_a[lidx]->layer_mask.top);
|
|
lyr_a[lidx]->layer_mask.left =
|
|
- GUINT32_FROM_BE (lyr_a[lidx]->layer_mask.left);
|
|
+ GINT32_FROM_BE (lyr_a[lidx]->layer_mask.left);
|
|
lyr_a[lidx]->layer_mask.bottom =
|
|
- GUINT32_FROM_BE (lyr_a[lidx]->layer_mask.bottom);
|
|
+ GINT32_FROM_BE (lyr_a[lidx]->layer_mask.bottom);
|
|
lyr_a[lidx]->layer_mask.right =
|
|
- GUINT32_FROM_BE (lyr_a[lidx]->layer_mask.right);
|
|
+ GINT32_FROM_BE (lyr_a[lidx]->layer_mask.right);
|
|
lyr_a[lidx]->layer_mask.mask_flags.relative_pos =
|
|
lyr_a[lidx]->layer_mask.flags & 1 ? TRUE : FALSE;
|
|
lyr_a[lidx]->layer_mask.mask_flags.disabled =
|
|
@@ -734,6 +755,34 @@ read_layer_block (PSDimage *img_a,
|
|
}
|
|
}
|
|
|
|
+ /* sanity checks */
|
|
+ if (lyr_a[lidx]->layer_mask.bottom < lyr_a[lidx]->layer_mask.top ||
|
|
+ lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top > GIMP_MAX_IMAGE_SIZE)
|
|
+ {
|
|
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
+ _("Unsupported or invalid layer mask height: %d"),
|
|
+ lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top);
|
|
+ return NULL;
|
|
+ }
|
|
+ if (lyr_a[lidx]->layer_mask.right < lyr_a[lidx]->layer_mask.left ||
|
|
+ lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left > GIMP_MAX_IMAGE_SIZE)
|
|
+ {
|
|
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
+ _("Unsupported or invalid layer mask width: %d"),
|
|
+ lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if ((lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left) >
|
|
+ G_MAXINT32 / MAX (lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top, 1))
|
|
+ {
|
|
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
+ _("Unsupported or invalid layer mask size: %dx%d"),
|
|
+ lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left,
|
|
+ lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
IFDBG(2) g_debug ("Layer mask coords %d %d %d %d, Rel pos %d",
|
|
lyr_a[lidx]->layer_mask.left,
|
|
lyr_a[lidx]->layer_mask.top,
|
|
@@ -1135,7 +1184,7 @@ add_layers (const gint32 image_id,
|
|
psd_set_error (feof (f), errno, error);
|
|
return -1;
|
|
}
|
|
- rle_pack_len[rowi] = GUINT16_FROM_BE (rle_pack_len[rowi]);
|
|
+ rle_pack_len[rowi] = GUINT16_FROM_BE (rle_pack_len[rowi]);
|
|
}
|
|
|
|
IFDBG(3) g_debug ("RLE decode - data");
|
|
@@ -1761,6 +1810,16 @@ read_channel_data (PSDchannel *channel,
|
|
|
|
IFDBG(3) g_debug ("raw data size %d x %d = %d", readline_len,
|
|
channel->rows, readline_len * channel->rows);
|
|
+
|
|
+ /* sanity check, int overflow check (avoid divisions by zero) */
|
|
+ if ((channel->rows == 0) || (channel->columns == 0) ||
|
|
+ (channel->rows > G_MAXINT32 / channel->columns / MAX (bps >> 3, 1)))
|
|
+ {
|
|
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
+ _("Unsupported or invalid channel size"));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
raw_data = g_malloc (readline_len * channel->rows);
|
|
switch (compression)
|
|
{
|
|
diff --git a/plug-ins/file-psd/psd.h b/plug-ins/file-psd/psd.h
|
|
index 6292747..b0c28ff 100644
|
|
--- a/plug-ins/file-psd/psd.h
|
|
+++ b/plug-ins/file-psd/psd.h
|
|
@@ -447,10 +447,10 @@ typedef struct
|
|
/* PSD Layer mask data (length 20) */
|
|
typedef struct
|
|
{
|
|
- guint32 top; /* Layer top */
|
|
- guint32 left; /* Layer left */
|
|
- guint32 bottom; /* Layer bottom */
|
|
- guint32 right; /* Layer right */
|
|
+ gint32 top; /* Layer top */
|
|
+ gint32 left; /* Layer left */
|
|
+ gint32 bottom; /* Layer bottom */
|
|
+ gint32 right; /* Layer right */
|
|
guchar def_color; /* Default background colour */
|
|
guchar flags; /* Layer flags */
|
|
guchar extra_def_color; /* Real default background colour */
|
|
@@ -461,20 +461,20 @@ typedef struct
|
|
/* PSD Layer mask data (length 36) */
|
|
typedef struct
|
|
{
|
|
- guint32 top; /* Layer top */
|
|
- guint32 left; /* Layer left */
|
|
- guint32 bottom; /* Layer bottom */
|
|
- guint32 right; /* Layer right */
|
|
+ gint32 top; /* Layer top */
|
|
+ gint32 left; /* Layer left */
|
|
+ gint32 bottom; /* Layer bottom */
|
|
+ gint32 right; /* Layer right */
|
|
} LayerMaskExtra;
|
|
|
|
/* PSD Layer data structure */
|
|
typedef struct
|
|
{
|
|
gboolean drop; /* Do not add layer to GIMP image */
|
|
- guint32 top; /* Layer top */
|
|
- guint32 left; /* Layer left */
|
|
- guint32 bottom; /* Layer bottom */
|
|
- guint32 right; /* Layer right */
|
|
+ gint32 top; /* Layer top */
|
|
+ gint32 left; /* Layer left */
|
|
+ gint32 bottom; /* Layer bottom */
|
|
+ gint32 right; /* Layer right */
|
|
guint16 num_channels; /* Number of channels */
|
|
ChannelLengthInfo *chn_info; /* Channel length info */
|
|
gchar mode_key[4]; /* Blend mode key */
|