rtpjpegpay: do some more sanitity checks

Protect some more against invalid input.
This commit is contained in:
Wim Taymans 2010-09-07 16:40:08 +02:00
parent a482677a14
commit 2ed53fd77f

View file

@ -302,7 +302,6 @@ invalid_dimension:
} }
} }
static guint static guint
gst_rtp_jpeg_pay_header_size (const guint8 * data, guint offset) gst_rtp_jpeg_pay_header_size (const guint8 * data, guint offset)
{ {
@ -310,70 +309,91 @@ gst_rtp_jpeg_pay_header_size (const guint8 * data, guint offset)
} }
static guint static guint
gst_rtp_jpeg_pay_read_quant_table (const guint8 * data, guint offset, gst_rtp_jpeg_pay_read_quant_table (const guint8 * data, guint size,
RtpQuantTable tables[], guint remainingBufferSize) guint offset, RtpQuantTable tables[])
{ {
gint quant_size, size, result; guint quant_size, tab_size;
guint8 prec; guint8 prec;
guint8 id; guint8 id;
result = quant_size = gst_rtp_jpeg_pay_header_size (data, offset); if (offset + 2 > size)
return size;
quant_size = gst_rtp_jpeg_pay_header_size (data, offset);
if (quant_size < 2)
return size;
/* clamp to available data */
if (offset + quant_size > size)
quant_size = size - offset;
offset += 2; offset += 2;
quant_size -= 2; quant_size -= 2;
/* Protect against rogue data by checking against remainingBufferSize */ while (quant_size > 0) {
while (quant_size > 0 && quant_size < remainingBufferSize) { /* not enough to read the id */
if (offset + 1 > size)
break;
id = data[offset] & 0xf; id = data[offset] & 0xf;
if (id == 15)
/* invalid id received - corrupt data */
break;
/* Protect against data corruption - limit to max number of quantization tables */ prec = (data[offset] & 0xf0) >> 4;
if (id < 15) { if (prec)
prec = (data[offset] & 0xf0) >> 4; tab_size = 128;
if (prec) else
size = 128; tab_size = 64;
else
size = 64;
GST_LOG ("read quant table %d, size %d, prec %02x", id, size, prec); /* there is not enough for the table */
if (quant_size < tab_size + 1)
break;
tables[id].size = size; GST_LOG ("read quant table %d, tab_size %d, prec %02x", id, tab_size, prec);
tables[id].data = &data[offset + 1];
size += 1; tables[id].size = tab_size;
quant_size -= size; tables[id].data = &data[offset + 1];
offset += size;
remainingBufferSize -= size; tab_size += 1;
} else { quant_size -= tab_size;
/*invalid id received - corrupt data */ offset += tab_size;
break; /* exit loop */
}
} }
return result; return offset + quant_size;
} }
static gboolean static gboolean
gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data, gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data,
guint * offset, CompInfo info[]) guint size, guint * offset, CompInfo info[])
{ {
guint sof_size; guint sof_size, off;
guint width, height, infolen; guint width, height, infolen;
CompInfo elem; CompInfo elem;
gint i, j; gint i, j;
sof_size = gst_rtp_jpeg_pay_header_size (data, *offset); off = *offset;
/* we need at least 17 bytes for the SOF */
if (off + 17 > size)
goto wrong_length;
sof_size = gst_rtp_jpeg_pay_header_size (data, off);
if (sof_size < 17) if (sof_size < 17)
goto wrong_length; goto wrong_length;
*offset += sof_size;
/* skip size */ /* skip size */
*offset += 2; off += 2;
/* precision should be 8 */ /* precision should be 8 */
if (data[(*offset)++] != 8) if (data[off++] != 8)
goto bad_precision; goto bad_precision;
/* read dimensions */ /* read dimensions */
height = data[*offset] << 8 | data[*offset + 1]; height = data[off] << 8 | data[off + 1];
width = data[*offset + 2] << 8 | data[*offset + 3]; width = data[off + 2] << 8 | data[off + 3];
*offset += 4; off += 4;
GST_LOG_OBJECT (pay, "got dimensions %ux%u", height, width); GST_LOG_OBJECT (pay, "got dimensions %ux%u", height, width);
@ -386,14 +406,14 @@ gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data,
pay->width = width / 8; pay->width = width / 8;
/* we only support 3 components */ /* we only support 3 components */
if (data[(*offset)++] != 3) if (data[off++] != 3)
goto bad_components; goto bad_components;
infolen = 0; infolen = 0;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
elem.id = data[(*offset)++]; elem.id = data[off++];
elem.samp = data[(*offset)++]; elem.samp = data[off++];
elem.qt = data[(*offset)++]; elem.qt = data[off++];
GST_LOG_OBJECT (pay, "got comp %d, samp %02x, qt %d", elem.id, elem.samp, GST_LOG_OBJECT (pay, "got comp %d, samp %02x, qt %d", elem.id, elem.samp,
elem.qt); elem.qt);
/* insertion sort from the last element to the first */ /* insertion sort from the last element to the first */
@ -470,8 +490,9 @@ gst_rtp_jpeg_pay_scan_marker (const guint8 * data, guint size, guint * offset)
} else { } else {
guint8 marker; guint8 marker;
marker = data[(*offset)++]; marker = data[*offset];
GST_LOG ("found %02x marker", marker); GST_LOG ("found %02x marker at offset %u", marker, *offset);
(*offset)++;
return marker; return marker;
} }
} }
@ -515,24 +536,24 @@ gst_rtp_jpeg_pay_handle_buffer (GstBaseRTPPayload * basepayload,
sos_found = FALSE; sos_found = FALSE;
dqt_found = FALSE; dqt_found = FALSE;
sof_found = FALSE; sof_found = FALSE;
while (!sos_found && (offset < size)) { while (!sos_found && (offset < size)) {
GST_LOG_OBJECT (pay, "checking from offset %u", offset); GST_LOG_OBJECT (pay, "checking from offset %u", offset);
switch (gst_rtp_jpeg_pay_scan_marker (data, size, &offset)) { switch (gst_rtp_jpeg_pay_scan_marker (data, size, &offset)) {
case JPEG_MARKER_JFIF: case JPEG_MARKER_JFIF:
case JPEG_MARKER_CMT: case JPEG_MARKER_CMT:
case JPEG_MARKER_DHT: case JPEG_MARKER_DHT:
GST_LOG_OBJECT (pay, "skipping marker");
offset += gst_rtp_jpeg_pay_header_size (data, offset); offset += gst_rtp_jpeg_pay_header_size (data, offset);
break; break;
case JPEG_MARKER_SOF: case JPEG_MARKER_SOF:
if (!gst_rtp_jpeg_pay_read_sof (pay, data, &offset, info)) if (!gst_rtp_jpeg_pay_read_sof (pay, data, size, &offset, info))
goto invalid_format; goto invalid_format;
sof_found = TRUE; sof_found = TRUE;
break; break;
case JPEG_MARKER_DQT: case JPEG_MARKER_DQT:
GST_LOG ("DQT found"); GST_LOG ("DQT found");
offset += offset = gst_rtp_jpeg_pay_read_quant_table (data, size, offset, tables);
gst_rtp_jpeg_pay_read_quant_table (data, offset, tables,
(size - offset));
dqt_found = TRUE; dqt_found = TRUE;
break; break;
case JPEG_MARKER_SOS: case JPEG_MARKER_SOS: