summaryrefslogtreecommitdiffstats
path: root/gst/qtdemux
diff options
context:
space:
mode:
authorTim-Philipp Müller <tim.muller@collabora.co.uk>2009-06-30 19:51:15 +0100
committerTim-Philipp Müller <tim.muller@collabora.co.uk>2009-09-23 16:54:42 +0100
commit4be46b15863f8c5cba3be89df1eada9b7db82752 (patch)
treec929b757014446ed97c89f549909003cee0439a9 /gst/qtdemux
parent5875e2016a0437b2127be00f0c95060b95aab668 (diff)
qtdemux: use bytereader to parse stsz and stsc atoms
Use GstByteReader to parse stsz and stsc chunks, and check size of available data before parsing it, instead of blindly assuming there will be enough data. Fixes crashes with some fuzzed/broken files.
Diffstat (limited to 'gst/qtdemux')
-rw-r--r--gst/qtdemux/qtdemux.c131
1 files changed, 99 insertions, 32 deletions
diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c
index 98514e2b..131d281c 100644
--- a/gst/qtdemux/qtdemux.c
+++ b/gst/qtdemux/qtdemux.c
@@ -246,6 +246,8 @@ enum QtDemuxState
};
static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
+static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
+ guint32 fourcc, QtAtomParser * parser);
static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
static const GstElementDetails gst_qtdemux_details =
@@ -3254,6 +3256,32 @@ qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
}
static GNode *
+qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
+ QtAtomParser * parser)
+{
+ GNode *child;
+ guint8 *buffer;
+ guint32 child_fourcc, child_len;
+
+ for (child = g_node_first_child (node); child;
+ child = g_node_next_sibling (child)) {
+ buffer = (guint8 *) child->data;
+
+ child_len = QT_UINT32 (buffer);
+ child_fourcc = QT_FOURCC (buffer + 4);
+
+ if (G_UNLIKELY (child_fourcc == fourcc)) {
+ if (G_UNLIKELY (child_len < (4 + 4)))
+ return NULL;
+ /* FIXME: must verify if atom length < parent atom length */
+ qt_atom_parser_init (parser, buffer + (4 + 4), child_len - (4 + 4));
+ return child;
+ }
+ }
+ return NULL;
+}
+
+static GNode *
qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
{
GNode *child;
@@ -3469,19 +3497,19 @@ static gboolean
qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
GNode * stbl)
{
- GNode *stsc;
- GNode *stsz;
+ QtAtomParser stsz;
+ QtAtomParser stsc;
GNode *stco;
GNode *co64;
GNode *stts;
GNode *stss;
GNode *stps;
GNode *ctts;
- const guint8 *stsc_data, *stsz_data, *stco_data, *co64_data, *stts_data;
- int sample_size;
+ const guint8 *stco_data, *co64_data, *stts_data;
+ guint32 sample_size;
+ guint32 n_samples;
+ guint32 n_samples_per_chunk;
int sample_index;
- int n_samples;
- int n_samples_per_chunk;
int n_sample_times;
QtDemuxSample *samples;
gint i, j, k;
@@ -3489,14 +3517,12 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
guint64 timestamp, time;
/* sample to chunk */
- if (!(stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc)))
+ if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stsc))
goto corrupt_file;
- stsc_data = (const guint8 *) stsc->data;
/* sample size */
- if (!(stsz = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsz)))
+ if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stsz))
goto corrupt_file;
- stsz_data = (const guint8 *) stsz->data;
/* chunk offsets */
stco = qtdemux_tree_get_child_by_type (stbl, FOURCC_stco);
@@ -3515,16 +3541,18 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
goto corrupt_file;
stts_data = (const guint8 *) stts->data;
- sample_size = QT_UINT32 (stsz_data + 12);
+ if (!qt_atom_parser_skip (&stsz, 1 + 3) ||
+ !qt_atom_parser_get_uint32 (&stsz, &sample_size))
+ goto corrupt_file;
+
if (sample_size == 0 || stream->sampled) {
- n_samples = QT_UINT32 (stsz_data + 16);
+ if (!qt_atom_parser_get_uint32 (&stsz, &n_samples))
+ goto corrupt_file;
if (n_samples == 0)
goto no_samples;
- else if (n_samples < 0)
- goto corrupt_file;
- GST_DEBUG_OBJECT (qtdemux, "stsz sample_size 0, allocating n_samples %d",
+ GST_DEBUG_OBJECT (qtdemux, "stsz sample_size 0, allocating n_samples %u",
n_samples);
samples = g_try_new0 (QtDemuxSample, n_samples);
@@ -3536,34 +3564,56 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
/* set the sample sizes */
if (sample_size == 0) {
- const guint8 *stsz_p = stsz_data + 20;
/* different sizes for each sample */
+ if (qt_atom_parser_get_remaining (&stsz) < 4 * (n_samples))
+ goto corrupt_file;
+
for (i = 0; i < n_samples; i++) {
- samples[i].size = QT_UINT32 (stsz_p);
- GST_LOG_OBJECT (qtdemux, "sample %d has size %d", i, samples[i].size);
- stsz_p += 4;
+ samples[i].size = qt_atom_parser_get_uint32_unchecked (&stsz);
+ GST_LOG_OBJECT (qtdemux, "sample %d has size %u", i, samples[i].size);
}
} else {
/* samples have the same size */
- GST_LOG_OBJECT (qtdemux, "all samples have size %d", sample_size);
+ GST_LOG_OBJECT (qtdemux, "all samples have size %u", sample_size);
for (i = 0; i < n_samples; i++)
samples[i].size = sample_size;
}
/* set the sample offsets in the file */
- n_samples_per_chunk = QT_UINT32 (stsc_data + 12);
+ if (!qt_atom_parser_skip (&stsc, 1 + 3) ||
+ !qt_atom_parser_get_uint32 (&stsc, &n_samples_per_chunk))
+ goto corrupt_file;
+
+ if (qt_atom_parser_get_remaining (&stsc) < 12 * n_samples_per_chunk)
+ goto corrupt_file;
+
index = 0;
for (i = 0; i < n_samples_per_chunk; i++) {
guint32 first_chunk, last_chunk;
guint32 samples_per_chunk;
- first_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 0) - 1;
+ first_chunk = qt_atom_parser_get_uint32_unchecked (&stsc);
+ samples_per_chunk = qt_atom_parser_get_uint32_unchecked (&stsc);
+ qt_atom_parser_skip_unchecked (&stsc, 4);
+
+ /* chunk numbers are counted from 1 it seems */
+ if (G_UNLIKELY (first_chunk == 0))
+ goto corrupt_file;
+ else
+ --first_chunk;
+
+ /* the last chunk of each entry is calculated by taking the first chunk
+ * of the next entry; except if there is no next, where we fake it with
+ * INT_MAX */
if (G_UNLIKELY (i == n_samples_per_chunk - 1)) {
last_chunk = G_MAXUINT32;
} else {
- last_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 12) - 1;
+ last_chunk = qt_atom_parser_peek_uint32_unchecked (&stsc);
+ if (G_UNLIKELY (last_chunk == 0))
+ goto corrupt_file;
+ else
+ --last_chunk;
}
- samples_per_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 4);
for (j = first_chunk; j < last_chunk; j++) {
guint64 chunk_offset;
@@ -3694,8 +3744,6 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
if (n_samples == 0)
goto no_samples;
- else if (n_samples < 0)
- goto corrupt_file;
GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %d", n_samples);
@@ -3706,24 +3754,43 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
stream->n_samples = n_samples;
stream->samples = samples;
- n_samples_per_chunk = QT_UINT32 (stsc_data + 12);
- GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %d", n_samples_per_chunk);
+ if (!qt_atom_parser_skip (&stsc, 1 + 3) ||
+ !qt_atom_parser_get_uint32 (&stsc, &n_samples_per_chunk))
+ goto corrupt_file;
+
+ GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u", n_samples_per_chunk);
sample_index = 0;
timestamp = 0;
+
+ if (qt_atom_parser_get_remaining (&stsc) < 12 * n_samples_per_chunk)
+ goto corrupt_file;
+
for (i = 0; i < n_samples_per_chunk; i++) {
guint32 first_chunk, last_chunk;
guint32 samples_per_chunk;
- first_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 0) - 1;
+ first_chunk = qt_atom_parser_get_uint32_unchecked (&stsc);
+ samples_per_chunk = qt_atom_parser_get_uint32_unchecked (&stsc);
+ qt_atom_parser_skip_unchecked (&stsc, 4);
+
+ /* chunk numbers are counted from 1 it seems */
+ if (G_UNLIKELY (first_chunk == 0))
+ goto corrupt_file;
+ else
+ --first_chunk;
+
/* the last chunk of each entry is calculated by taking the first chunk
* of the next entry; except if there is no next, where we fake it with
* INT_MAX */
- if (i == n_samples_per_chunk - 1) {
+ if (G_UNLIKELY (i == (n_samples_per_chunk - 1))) {
last_chunk = G_MAXUINT32;
} else {
- last_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 12) - 1;
+ last_chunk = qt_atom_parser_peek_uint32_unchecked (&stsc);
+ if (G_UNLIKELY (last_chunk == 0))
+ goto corrupt_file;
+ else
+ --last_chunk;
}
- samples_per_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 4);
GST_LOG_OBJECT (qtdemux,
"entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,