flxdec: add some write bounds checking
Without checking the bounds of the frame we are writing into, we can write off the end of the destination buffer. https://scarybeastsecurity.blogspot.dk/2016/11/0day-exploit-advancing-exploitation.html https://bugzilla.gnome.org/show_bug.cgi?id=774834
This commit is contained in:
parent
45843ab9a2
commit
bf43f44fcf
@ -74,9 +74,9 @@ static gboolean gst_flxdec_src_query_handler (GstPad * pad, GstObject * parent,
|
|||||||
GstQuery * query);
|
GstQuery * query);
|
||||||
|
|
||||||
static void flx_decode_color (GstFlxDec *, guchar *, guchar *, gint);
|
static void flx_decode_color (GstFlxDec *, guchar *, guchar *, gint);
|
||||||
static void flx_decode_brun (GstFlxDec *, guchar *, guchar *);
|
static gboolean flx_decode_brun (GstFlxDec *, guchar *, guchar *);
|
||||||
static void flx_decode_delta_fli (GstFlxDec *, guchar *, guchar *);
|
static gboolean flx_decode_delta_fli (GstFlxDec *, guchar *, guchar *);
|
||||||
static void flx_decode_delta_flc (GstFlxDec *, guchar *, guchar *);
|
static gboolean flx_decode_delta_flc (GstFlxDec *, guchar *, guchar *);
|
||||||
|
|
||||||
#define rndalign(off) ((off) + ((off) & 1))
|
#define rndalign(off) ((off) + ((off) & 1))
|
||||||
|
|
||||||
@ -203,13 +203,14 @@ gst_flxdec_sink_event_handler (GstPad * pad, GstObject * parent,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
|
flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
|
||||||
guchar * dest)
|
guchar * dest)
|
||||||
{
|
{
|
||||||
FlxFrameChunk *hdr;
|
FlxFrameChunk *hdr;
|
||||||
|
gboolean ret = TRUE;
|
||||||
|
|
||||||
g_return_if_fail (data != NULL);
|
g_return_val_if_fail (data != NULL, FALSE);
|
||||||
|
|
||||||
while (count--) {
|
while (count--) {
|
||||||
hdr = (FlxFrameChunk *) data;
|
hdr = (FlxFrameChunk *) data;
|
||||||
@ -228,17 +229,17 @@ flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FLX_BRUN:
|
case FLX_BRUN:
|
||||||
flx_decode_brun (flxdec, data, dest);
|
ret = flx_decode_brun (flxdec, data, dest);
|
||||||
data += rndalign (hdr->size) - FlxFrameChunkSize;
|
data += rndalign (hdr->size) - FlxFrameChunkSize;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FLX_LC:
|
case FLX_LC:
|
||||||
flx_decode_delta_fli (flxdec, data, dest);
|
ret = flx_decode_delta_fli (flxdec, data, dest);
|
||||||
data += rndalign (hdr->size) - FlxFrameChunkSize;
|
data += rndalign (hdr->size) - FlxFrameChunkSize;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FLX_SS2:
|
case FLX_SS2:
|
||||||
flx_decode_delta_flc (flxdec, data, dest);
|
ret = flx_decode_delta_flc (flxdec, data, dest);
|
||||||
data += rndalign (hdr->size) - FlxFrameChunkSize;
|
data += rndalign (hdr->size) - FlxFrameChunkSize;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -256,7 +257,12 @@ flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
|
|||||||
data += rndalign (hdr->size) - FlxFrameChunkSize;
|
data += rndalign (hdr->size) - FlxFrameChunkSize;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -289,13 +295,13 @@ flx_decode_color (GstFlxDec * flxdec, guchar * data, guchar * dest, gint scale)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
||||||
{
|
{
|
||||||
gulong count, lines, row;
|
gulong count, lines, row;
|
||||||
guchar x;
|
guchar x;
|
||||||
|
|
||||||
g_return_if_fail (flxdec != NULL);
|
g_return_val_if_fail (flxdec != NULL, FALSE);
|
||||||
|
|
||||||
lines = flxdec->hdr.height;
|
lines = flxdec->hdr.height;
|
||||||
while (lines--) {
|
while (lines--) {
|
||||||
@ -313,12 +319,21 @@ flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
|||||||
if (count > 0x7f) {
|
if (count > 0x7f) {
|
||||||
/* literal run */
|
/* literal run */
|
||||||
count = 0x100 - count;
|
count = 0x100 - count;
|
||||||
|
if ((glong) row - count < 0) {
|
||||||
|
GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
row -= count;
|
row -= count;
|
||||||
|
|
||||||
while (count--)
|
while (count--)
|
||||||
*dest++ = *data++;
|
*dest++ = *data++;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
if ((glong) row - count < 0) {
|
||||||
|
GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* replicate run */
|
/* replicate run */
|
||||||
row -= count;
|
row -= count;
|
||||||
x = *data++;
|
x = *data++;
|
||||||
@ -328,22 +343,28 @@ flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
||||||
{
|
{
|
||||||
gulong count, packets, lines, start_line;
|
gulong count, packets, lines, start_line;
|
||||||
guchar *start_p, x;
|
guchar *start_p, x;
|
||||||
|
|
||||||
g_return_if_fail (flxdec != NULL);
|
g_return_val_if_fail (flxdec != NULL, FALSE);
|
||||||
g_return_if_fail (flxdec->delta_data != NULL);
|
g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
|
||||||
|
|
||||||
/* use last frame for delta */
|
/* use last frame for delta */
|
||||||
memcpy (dest, flxdec->delta_data, flxdec->size);
|
memcpy (dest, flxdec->delta_data, flxdec->size);
|
||||||
|
|
||||||
start_line = (data[0] + (data[1] << 8));
|
start_line = (data[0] + (data[1] << 8));
|
||||||
lines = (data[2] + (data[3] << 8));
|
lines = (data[2] + (data[3] << 8));
|
||||||
|
if (start_line + lines > flxdec->hdr.height) {
|
||||||
|
GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. too many lines.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
data += 4;
|
data += 4;
|
||||||
|
|
||||||
/* start position of delta */
|
/* start position of delta */
|
||||||
@ -356,7 +377,8 @@ flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
|||||||
|
|
||||||
while (packets--) {
|
while (packets--) {
|
||||||
/* skip count */
|
/* skip count */
|
||||||
dest += *data++;
|
guchar skip = *data++;
|
||||||
|
dest += skip;
|
||||||
|
|
||||||
/* RLE count */
|
/* RLE count */
|
||||||
count = *data++;
|
count = *data++;
|
||||||
@ -364,12 +386,24 @@ flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
|||||||
if (count > 0x7f) {
|
if (count > 0x7f) {
|
||||||
/* literal run */
|
/* literal run */
|
||||||
count = 0x100 - count;
|
count = 0x100 - count;
|
||||||
x = *data++;
|
|
||||||
|
|
||||||
|
if (skip + count > flxdec->hdr.width) {
|
||||||
|
GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
|
||||||
|
"line too long.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = *data++;
|
||||||
while (count--)
|
while (count--)
|
||||||
*dest++ = x;
|
*dest++ = x;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
if (skip + count > flxdec->hdr.width) {
|
||||||
|
GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
|
||||||
|
"line too long.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* replicate run */
|
/* replicate run */
|
||||||
while (count--)
|
while (count--)
|
||||||
*dest++ = *data++;
|
*dest++ = *data++;
|
||||||
@ -378,21 +412,27 @@ flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
|||||||
start_p += flxdec->hdr.width;
|
start_p += flxdec->hdr.width;
|
||||||
dest = start_p;
|
dest = start_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
||||||
{
|
{
|
||||||
gulong count, lines, start_l, opcode;
|
gulong count, lines, start_l, opcode;
|
||||||
guchar *start_p;
|
guchar *start_p;
|
||||||
|
|
||||||
g_return_if_fail (flxdec != NULL);
|
g_return_val_if_fail (flxdec != NULL, FALSE);
|
||||||
g_return_if_fail (flxdec->delta_data != NULL);
|
g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
|
||||||
|
|
||||||
/* use last frame for delta */
|
/* use last frame for delta */
|
||||||
memcpy (dest, flxdec->delta_data, flxdec->size);
|
memcpy (dest, flxdec->delta_data, flxdec->size);
|
||||||
|
|
||||||
lines = (data[0] + (data[1] << 8));
|
lines = (data[0] + (data[1] << 8));
|
||||||
|
if (lines > flxdec->hdr.height) {
|
||||||
|
GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. too many lines.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
data += 2;
|
data += 2;
|
||||||
|
|
||||||
start_p = dest;
|
start_p = dest;
|
||||||
@ -405,9 +445,15 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
|||||||
while ((opcode = (data[0] + (data[1] << 8))) & 0xc000) {
|
while ((opcode = (data[0] + (data[1] << 8))) & 0xc000) {
|
||||||
data += 2;
|
data += 2;
|
||||||
if ((opcode & 0xc000) == 0xc000) {
|
if ((opcode & 0xc000) == 0xc000) {
|
||||||
/* skip count */
|
/* line skip count */
|
||||||
start_l += (0x10000 - opcode);
|
gulong skip = (0x10000 - opcode);
|
||||||
dest += flxdec->hdr.width * (0x10000 - opcode);
|
if (skip > flxdec->hdr.height) {
|
||||||
|
GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
|
||||||
|
"skip line count too big.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
start_l += skip;
|
||||||
|
dest += flxdec->hdr.width * skip;
|
||||||
} else {
|
} else {
|
||||||
/* last pixel */
|
/* last pixel */
|
||||||
dest += flxdec->hdr.width;
|
dest += flxdec->hdr.width;
|
||||||
@ -419,7 +465,8 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
|||||||
/* last opcode is the packet count */
|
/* last opcode is the packet count */
|
||||||
while (opcode--) {
|
while (opcode--) {
|
||||||
/* skip count */
|
/* skip count */
|
||||||
dest += *data++;
|
guchar skip = *data++;
|
||||||
|
dest += skip;
|
||||||
|
|
||||||
/* RLE count */
|
/* RLE count */
|
||||||
count = *data++;
|
count = *data++;
|
||||||
@ -427,12 +474,25 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
|||||||
if (count > 0x7f) {
|
if (count > 0x7f) {
|
||||||
/* replicate word run */
|
/* replicate word run */
|
||||||
count = 0x100 - count;
|
count = 0x100 - count;
|
||||||
|
|
||||||
|
if (skip + count > flxdec->hdr.width) {
|
||||||
|
GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
|
||||||
|
"line too long.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*dest++ = data[0];
|
*dest++ = data[0];
|
||||||
*dest++ = data[1];
|
*dest++ = data[1];
|
||||||
}
|
}
|
||||||
data += 2;
|
data += 2;
|
||||||
} else {
|
} else {
|
||||||
|
if (skip + count > flxdec->hdr.width) {
|
||||||
|
GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
|
||||||
|
"line too long.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* literal word run */
|
/* literal word run */
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*dest++ = *data++;
|
*dest++ = *data++;
|
||||||
@ -442,6 +502,8 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
|||||||
}
|
}
|
||||||
lines--;
|
lines--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
@ -571,9 +633,13 @@ gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
|||||||
out = gst_buffer_new_and_alloc (flxdec->size * 4);
|
out = gst_buffer_new_and_alloc (flxdec->size * 4);
|
||||||
|
|
||||||
/* decode chunks */
|
/* decode chunks */
|
||||||
flx_decode_chunks (flxdec,
|
if (!flx_decode_chunks (flxdec,
|
||||||
((FlxFrameType *) chunk)->chunks,
|
((FlxFrameType *) chunk)->chunks,
|
||||||
chunk + FlxFrameTypeSize, flxdec->frame_data);
|
chunk + FlxFrameTypeSize, flxdec->frame_data)) {
|
||||||
|
GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
|
||||||
|
("%s", "Could not decode chunk"), NULL);
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/* save copy of the current frame for possible delta. */
|
/* save copy of the current frame for possible delta. */
|
||||||
memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size);
|
memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user