mirror of https://github.com/mpv-player/mpv
demux_mkv: add some overflow checks etc.
Some of these might be security relevant. The RealAudio code was especially bad. I'm not sure if all RealAudio stuff still plays correctly; I didn't have that many samples for testing. Some checks might be unnecessary or overcomplicated compared to the (obfuscated) nature of the code. CC: @mpv-player/stable
This commit is contained in:
parent
1646584058
commit
37251cef69
|
@ -128,13 +128,13 @@ typedef struct mkv_track {
|
|||
double ra_pts; /* previous audio timestamp */
|
||||
|
||||
/** realaudio descrambling */
|
||||
int sub_packet_size; ///< sub packet size, per stream
|
||||
int sub_packet_h; ///< number of coded frames per block
|
||||
int coded_framesize; ///< coded frame size, per stream
|
||||
int audiopk_size; ///< audio packet size
|
||||
uint16_t sub_packet_size; ///< sub packet size, per stream
|
||||
uint16_t sub_packet_h; ///< number of coded frames per block
|
||||
uint32_t coded_framesize; ///< coded frame size, per stream
|
||||
uint16_t audiopk_size; ///< audio packet size
|
||||
unsigned char *audio_buf; ///< place to store reordered audio data
|
||||
double *audio_timestamp; ///< timestamp for each audio packet
|
||||
int sub_packet_cnt; ///< number of subpacket already received
|
||||
uint16_t sub_packet_cnt; ///< number of subpacket already received
|
||||
int audio_filepos; ///< file position of first audio packet in block
|
||||
|
||||
/* generic content encoding support */
|
||||
|
@ -142,7 +142,7 @@ typedef struct mkv_track {
|
|||
int num_encodings;
|
||||
|
||||
/* latest added index entry for this track */
|
||||
int last_index_entry;
|
||||
size_t last_index_entry;
|
||||
} mkv_track_t;
|
||||
|
||||
typedef struct mkv_index {
|
||||
|
@ -167,7 +167,7 @@ typedef struct mkv_demuxer {
|
|||
uint64_t cluster_end;
|
||||
|
||||
mkv_index_t *indexes;
|
||||
int num_indexes;
|
||||
size_t num_indexes;
|
||||
bool index_complete;
|
||||
uint64_t deferred_cues;
|
||||
|
||||
|
@ -192,19 +192,6 @@ typedef struct mkv_demuxer {
|
|||
// (Subtitle packets added before first A/V keyframe packet is found with seek.)
|
||||
#define NUM_SUB_PREROLL_PACKETS 500
|
||||
|
||||
/**
|
||||
* \brief ensures there is space for at least one additional element
|
||||
* \param array array to grow
|
||||
* \param nelem current number of elements in array
|
||||
* \param elsize size of one array element
|
||||
*/
|
||||
static void *grow_array(void *array, int nelem, size_t elsize)
|
||||
{
|
||||
if (!(nelem & 31))
|
||||
array = realloc(array, (nelem + 32) * elsize);
|
||||
return array;
|
||||
}
|
||||
|
||||
#define AAC_SYNC_EXTENSION_TYPE 0x02b7
|
||||
static int aac_get_sample_rate_index(uint32_t sample_rate)
|
||||
{
|
||||
|
@ -258,6 +245,12 @@ static bstr demux_mkv_decode(struct mp_log *log, mkv_track_t *track,
|
|||
zstream.avail_out = size;
|
||||
int result;
|
||||
do {
|
||||
if (size >= INT_MAX - 4000) {
|
||||
talloc_free(dest);
|
||||
dest = NULL;
|
||||
inflateEnd(&zstream);
|
||||
goto error;
|
||||
}
|
||||
size += 4000;
|
||||
dest = talloc_realloc_size(track->parser_tmp, dest, size);
|
||||
zstream.next_out = (Bytef *) (dest + zstream.total_out);
|
||||
|
@ -279,6 +272,8 @@ static bstr demux_mkv_decode(struct mp_log *log, mkv_track_t *track,
|
|||
} else if (enc->comp_algo == 2) {
|
||||
/* lzo encoded track */
|
||||
int out_avail;
|
||||
if (size > INT_MAX / 3 + AV_LZO_OUTPUT_PADDING)
|
||||
goto error;
|
||||
int dstlen = size * 3;
|
||||
|
||||
dest = NULL;
|
||||
|
@ -297,6 +292,11 @@ static bstr demux_mkv_decode(struct mp_log *log, mkv_track_t *track,
|
|||
goto error;
|
||||
}
|
||||
mp_dbg(log, "lzo decompression buffer too small.\n");
|
||||
if (dstlen > INT_MAX / 2 + AV_LZO_OUTPUT_PADDING) {
|
||||
talloc_free(dest);
|
||||
dest = NULL;
|
||||
goto error;
|
||||
}
|
||||
dstlen *= 2;
|
||||
}
|
||||
size = dstlen - out_avail;
|
||||
|
@ -311,6 +311,8 @@ static bstr demux_mkv_decode(struct mp_log *log, mkv_track_t *track,
|
|||
error:
|
||||
if (src != dest && src != orig_src)
|
||||
talloc_free(src);
|
||||
if (!size)
|
||||
dest = NULL;
|
||||
return (bstr){dest, size};
|
||||
}
|
||||
|
||||
|
@ -433,7 +435,7 @@ static void parse_trackencodings(struct demuxer *demuxer,
|
|||
if (e.order >= ce[i].order)
|
||||
break;
|
||||
}
|
||||
ce = talloc_realloc_size(track, ce, (n_enc + 1) * sizeof(*ce));
|
||||
ce = talloc_realloc(track, ce, mkv_content_encoding_t, n_enc + 1);
|
||||
memmove(ce + i + 1, ce + i, (n_enc - i) * sizeof(*ce));
|
||||
memcpy(ce + i, &e, sizeof(e));
|
||||
}
|
||||
|
@ -525,8 +527,8 @@ static void parse_trackentry(struct demuxer *demuxer,
|
|||
struct ebml_track_entry *entry)
|
||||
{
|
||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||
struct mkv_track *track = talloc_zero_size(NULL, sizeof(*track));
|
||||
track->last_index_entry = -1;
|
||||
struct mkv_track *track = talloc_zero(NULL, struct mkv_track);
|
||||
track->last_index_entry = (size_t)-1;
|
||||
track->parser_tmp = talloc_new(track);
|
||||
|
||||
track->tnum = entry->track_number;
|
||||
|
@ -584,7 +586,7 @@ static void parse_trackentry(struct demuxer *demuxer,
|
|||
track->codec_id = "";
|
||||
}
|
||||
|
||||
if (entry->n_codec_private) {
|
||||
if (entry->n_codec_private && entry->codec_private.len <= 0x1000000) {
|
||||
int len = entry->codec_private.len;
|
||||
track->private_data = talloc_size(track, len + AV_LZO_INPUT_PADDING);
|
||||
memcpy(track->private_data, entry->codec_private.start, len);
|
||||
|
@ -640,8 +642,8 @@ static int demux_mkv_read_tracks(demuxer_t *demuxer)
|
|||
if (ebml_read_element(s, &parse_ctx, &tracks, &ebml_tracks_desc) < 0)
|
||||
return -1;
|
||||
|
||||
mkv_d->tracks = talloc_size(mkv_d,
|
||||
tracks.n_track_entry * sizeof(*mkv_d->tracks));
|
||||
mkv_d->tracks = talloc_zero_array(mkv_d, struct mkv_track*,
|
||||
tracks.n_track_entry);
|
||||
for (int i = 0; i < tracks.n_track_entry; i++) {
|
||||
MP_VERBOSE(demuxer, "| + a track...\n");
|
||||
parse_trackentry(demuxer, &tracks.track_entry[i]);
|
||||
|
@ -655,8 +657,8 @@ static void cue_index_add(demuxer_t *demuxer, int track_id, uint64_t filepos,
|
|||
{
|
||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||
|
||||
mkv_d->indexes = grow_array(mkv_d->indexes, mkv_d->num_indexes,
|
||||
sizeof(mkv_index_t));
|
||||
MP_TARRAY_GROW(mkv_d, mkv_d->indexes, mkv_d->num_indexes);
|
||||
|
||||
mkv_d->indexes[mkv_d->num_indexes].tnum = track_id;
|
||||
mkv_d->indexes[mkv_d->num_indexes].timecode = timecode;
|
||||
mkv_d->indexes[mkv_d->num_indexes].filepos = filepos;
|
||||
|
@ -670,7 +672,7 @@ static void add_block_position(demuxer_t *demuxer, struct mkv_track *track,
|
|||
|
||||
if (mkv_d->index_complete || !track)
|
||||
return;
|
||||
if (track->last_index_entry >= 0) {
|
||||
if (track->last_index_entry != (size_t)-1) {
|
||||
mkv_index_t *index = &mkv_d->indexes[track->last_index_entry];
|
||||
// filepos is always the cluster position, which can contain multiple
|
||||
// blocks with different timecodes - one is enough.
|
||||
|
@ -1241,6 +1243,11 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
|
|||
}
|
||||
}
|
||||
|
||||
if (extradata_size > 0x1000000) {
|
||||
MP_WARN(demuxer, "Invalid CodecPrivate\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sh = new_sh_stream(demuxer, STREAM_VIDEO);
|
||||
if (!sh)
|
||||
return 1;
|
||||
|
@ -1465,6 +1472,8 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
|
|||
if (track->private_size == 0 || track->ms_compat && !sh_a->wf->cbSize)
|
||||
goto error;
|
||||
if (!track->ms_compat) {
|
||||
if (track->private_size > 0x1000000)
|
||||
goto error;
|
||||
sh_a->wf->cbSize = track->private_size;
|
||||
sh_a->wf = talloc_realloc_size(sh_a, sh_a->wf,
|
||||
sizeof(*sh_a->wf) + sh_a->wf->cbSize);
|
||||
|
@ -1499,10 +1508,18 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
|
|||
src += RAPROPERTIES5_SIZE;
|
||||
}
|
||||
|
||||
if (track->audiopk_size == 0 || track->sub_packet_size == 0 ||
|
||||
track->sub_packet_h == 0 || track->coded_framesize == 0)
|
||||
goto error;
|
||||
if (track->coded_framesize > 0x40000000)
|
||||
goto error;
|
||||
|
||||
src += 3;
|
||||
if (version == 5)
|
||||
src++;
|
||||
codecdata_length = AV_RB32(src);
|
||||
if (codecdata_length < 0 || codecdata_length > 0x1000000)
|
||||
goto error;
|
||||
src += 4;
|
||||
sh_a->wf->cbSize = codecdata_length;
|
||||
sh_a->wf = talloc_realloc_size(sh_a, sh_a->wf,
|
||||
|
@ -1527,9 +1544,9 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
|
|||
sh_a->wf->nBlockAlign = track->coded_framesize;
|
||||
audiobuf:
|
||||
track->audio_buf =
|
||||
talloc_size(demuxer, track->sub_packet_h * track->audiopk_size);
|
||||
talloc_array_size(track, track->sub_packet_h, track->audiopk_size);
|
||||
track->audio_timestamp =
|
||||
talloc_size(demuxer, track->sub_packet_h * sizeof(double));
|
||||
talloc_array(track, double, track->sub_packet_h);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1631,6 +1648,9 @@ static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track)
|
|||
}
|
||||
}
|
||||
|
||||
if (track->private_size > 0x10000000)
|
||||
return 1;
|
||||
|
||||
bstr in = (bstr){track->private_data, track->private_size};
|
||||
struct sh_stream *sh = new_sh_stream(demuxer, STREAM_SUB);
|
||||
if (!sh)
|
||||
|
@ -1989,46 +2009,63 @@ static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
|
|||
bstr data, bool keyframe)
|
||||
{
|
||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||
int sps = track->sub_packet_size;
|
||||
int sph = track->sub_packet_h;
|
||||
int cfs = track->coded_framesize;
|
||||
int w = track->audiopk_size;
|
||||
int spc = track->sub_packet_cnt;
|
||||
uint16_t sps = track->sub_packet_size;
|
||||
uint16_t sph = track->sub_packet_h;
|
||||
uint32_t cfs = track->coded_framesize; // restricted to [1,0x40000000]
|
||||
uint16_t w = track->audiopk_size;
|
||||
uint16_t spc = track->sub_packet_cnt;
|
||||
uint8_t *buffer = data.start;
|
||||
uint32_t size = data.len;
|
||||
demux_packet_t *dp;
|
||||
|
||||
// track->audio_buf allocation size
|
||||
size_t audiobuf_size = sph * w;
|
||||
|
||||
if ((track->a_formattag == MP_FOURCC('2', '8', '_', '8'))
|
||||
|| (track->a_formattag == MP_FOURCC('c', 'o', 'o', 'k'))
|
||||
|| (track->a_formattag == MP_FOURCC('a', 't', 'r', 'c'))
|
||||
|| (track->a_formattag == MP_FOURCC('s', 'i', 'p', 'r'))) {
|
||||
// if(!block_bref)
|
||||
// spc = track->sub_packet_cnt = 0;
|
||||
|| (track->a_formattag == MP_FOURCC('s', 'i', 'p', 'r')))
|
||||
{
|
||||
switch (track->a_formattag) {
|
||||
case MP_FOURCC('2', '8', '_', '8'):
|
||||
for (int x = 0; x < sph / 2; x++)
|
||||
memcpy(track->audio_buf + x * 2 * w + spc * cfs,
|
||||
buffer + cfs * x, cfs);
|
||||
for (int x = 0; x < sph / 2; x++) {
|
||||
uint64_t dst_offset = x * 2 * w + spc * (uint64_t)cfs;
|
||||
if (dst_offset + cfs > audiobuf_size)
|
||||
goto error;
|
||||
uint64_t src_offset = x * (uint64_t)cfs;
|
||||
if (src_offset + cfs > size)
|
||||
goto error;
|
||||
memcpy(track->audio_buf + dst_offset, buffer + src_offset, cfs);
|
||||
}
|
||||
break;
|
||||
case MP_FOURCC('c', 'o', 'o', 'k'):
|
||||
case MP_FOURCC('a', 't', 'r', 'c'):
|
||||
for (int x = 0; x < w / sps; x++)
|
||||
memcpy(track->audio_buf +
|
||||
sps * (sph * x + ((sph + 1) / 2) * (spc & 1) +
|
||||
(spc >> 1)), buffer + sps * x, sps);
|
||||
for (int x = 0; x < w / sps; x++) {
|
||||
uint32_t dst_offset = sps * (sph * x + ((sph + 1) / 2) * (spc & 1)
|
||||
+ (spc >> 1));
|
||||
if (dst_offset + sps > audiobuf_size)
|
||||
goto error;
|
||||
uint32_t src_offset = sps * x;
|
||||
if (src_offset + sps > size)
|
||||
goto error;
|
||||
memcpy(track->audio_buf + dst_offset, buffer + src_offset, sps);
|
||||
}
|
||||
break;
|
||||
case MP_FOURCC('s', 'i', 'p', 'r'):
|
||||
if (spc * w + w > audiobuf_size || w > size)
|
||||
goto error;
|
||||
memcpy(track->audio_buf + spc * w, buffer, w);
|
||||
if (spc == sph - 1) {
|
||||
int n;
|
||||
int bs = sph * w * 2 / 96; // nibbles per subpacket
|
||||
// Perform reordering
|
||||
for (n = 0; n < 38; n++) {
|
||||
int j;
|
||||
int i = bs * sipr_swaps[n][0];
|
||||
int o = bs * sipr_swaps[n][1];
|
||||
// swap nibbles of block 'i' with 'o' TODO: optimize
|
||||
for (j = 0; j < bs; j++) {
|
||||
int i = bs * sipr_swaps[n][0]; // 77 max
|
||||
int o = bs * sipr_swaps[n][1]; // 95 max
|
||||
// swap nibbles of block 'i' with 'o'
|
||||
for (int j = 0; j < bs; j++) {
|
||||
if (i / 2 >= audiobuf_size || o / 2 >= audiobuf_size)
|
||||
goto error;
|
||||
int x = (i & 1) ?
|
||||
(track->audio_buf[i >> 1] >> 4) :
|
||||
(track->audio_buf[i >> 1] & 0x0F);
|
||||
|
@ -2060,8 +2097,11 @@ static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
|
|||
if (track->sub_packet_cnt == 0)
|
||||
track->audio_filepos = mkv_d->last_filepos;
|
||||
if (++(track->sub_packet_cnt) == sph) {
|
||||
int apk_usize = track->stream->audio->wf->nBlockAlign;
|
||||
track->sub_packet_cnt = 0;
|
||||
// apk_usize has same range as coded_framesize in worst case
|
||||
uint32_t apk_usize = track->stream->audio->wf->nBlockAlign;
|
||||
if (apk_usize > audiobuf_size)
|
||||
goto error;
|
||||
// Release all the audio packets
|
||||
for (int x = 0; x < sph * w / apk_usize; x++) {
|
||||
dp = new_demux_packet_from(track->audio_buf + x * apk_usize,
|
||||
|
@ -2087,6 +2127,9 @@ static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
|
|||
dp->keyframe = keyframe;
|
||||
demuxer_add_packet(demuxer, track->stream, dp);
|
||||
}
|
||||
return;
|
||||
error:
|
||||
MP_ERR(demuxer, "RealAudio decrypting error.\n");
|
||||
}
|
||||
|
||||
static void mkv_seek_reset(demuxer_t *demuxer)
|
||||
|
@ -2154,6 +2197,9 @@ static int libav_parse_wavpack(mkv_track_t *track, uint8_t *src,
|
|||
if (blocksize > srclen)
|
||||
goto fail;
|
||||
|
||||
if (dstlen > 0x10000000 || blocksize > 0x10000000)
|
||||
goto fail;
|
||||
|
||||
tmp = talloc_realloc(track->parser_tmp, dst, uint8_t,
|
||||
dstlen + blocksize + 32);
|
||||
if (!tmp)
|
||||
|
@ -2223,7 +2269,7 @@ static bool mkv_parse_packet(mkv_track_t *track, bstr *raw, bstr *out)
|
|||
int len = av_parser_parse2(track->av_parser, track->av_parser_codec,
|
||||
&data, &size, raw->start, raw->len,
|
||||
AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
|
||||
if (len < 0)
|
||||
if (len < 0 || len > 0x10000000)
|
||||
return false;
|
||||
*raw = bstr_cut(*raw, len);
|
||||
if (size) {
|
||||
|
@ -2640,7 +2686,7 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id,
|
|||
min_diff = -min_diff;
|
||||
min_diff = FFMAX(min_diff, 1);
|
||||
|
||||
for (int i = 0; i < mkv_d->num_indexes; i++) {
|
||||
for (size_t i = 0; i < mkv_d->num_indexes; i++) {
|
||||
if (seek_id < 0 || mkv_d->indexes[i].tnum == seek_id) {
|
||||
int64_t diff =
|
||||
target_timecode -
|
||||
|
@ -2661,7 +2707,7 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id,
|
|||
uint64_t seek_pos = index->filepos;
|
||||
if (flags & SEEK_SUBPREROLL) {
|
||||
uint64_t prev_target = 0;
|
||||
for (int i = 0; i < mkv_d->num_indexes; i++) {
|
||||
for (size_t i = 0; i < mkv_d->num_indexes; i++) {
|
||||
if (seek_id < 0 || mkv_d->indexes[i].tnum == seek_id) {
|
||||
uint64_t index_pos = mkv_d->indexes[i].filepos;
|
||||
if (index_pos > prev_target && index_pos < seek_pos)
|
||||
|
@ -2745,7 +2791,6 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, int flags)
|
|||
stream_t *s = demuxer->stream;
|
||||
uint64_t target_filepos;
|
||||
mkv_index_t *index = NULL;
|
||||
int i;
|
||||
|
||||
read_deferred_cues(demuxer);
|
||||
|
||||
|
@ -2759,7 +2804,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, int flags)
|
|||
stream_control(s, STREAM_CTRL_GET_SIZE, &size);
|
||||
|
||||
target_filepos = (uint64_t) (size * rel_seek_secs);
|
||||
for (i = 0; i < mkv_d->num_indexes; i++)
|
||||
for (size_t i = 0; i < mkv_d->num_indexes; i++)
|
||||
if (mkv_d->indexes[i].tnum == v_tnum)
|
||||
if ((index == NULL)
|
||||
|| ((mkv_d->indexes[i].filepos >= target_filepos)
|
||||
|
@ -2807,7 +2852,6 @@ static void mkv_free(struct demuxer *demuxer)
|
|||
mkv_seek_reset(demuxer);
|
||||
for (int i = 0; i < mkv_d->num_tracks; i++)
|
||||
demux_mkv_free_trackentry(mkv_d->tracks[i]);
|
||||
free(mkv_d->indexes);
|
||||
}
|
||||
|
||||
const demuxer_desc_t demuxer_desc_matroska = {
|
||||
|
|
10
demux/ebml.c
10
demux/ebml.c
|
@ -364,7 +364,7 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
|||
char *s = target;
|
||||
uint8_t *end = data + size;
|
||||
uint8_t *p = data;
|
||||
int num_elems[MAX_EBML_SUBELEMENTS] = {};
|
||||
int num_elems[MAX_EBML_SUBELEMENTS] = {0};
|
||||
while (p < end) {
|
||||
uint8_t *startp = p;
|
||||
int len;
|
||||
|
@ -390,6 +390,10 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
|||
if (type->fields[i].id == id) {
|
||||
field_idx = i;
|
||||
num_elems[i]++;
|
||||
if (num_elems[i] >= 0x70000000) {
|
||||
MP_ERR(ctx, "Too many EBML subelements.\n");
|
||||
goto other_error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -566,6 +570,10 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
|||
|
||||
case EBML_TYPE_STR:
|
||||
case EBML_TYPE_BINARY:;
|
||||
if (length > 0x80000000) {
|
||||
MP_ERR(ctx, "Not reading overly long EBML element.\n");
|
||||
break;
|
||||
}
|
||||
struct bstr *strptr;
|
||||
GETPTR(strptr, struct bstr);
|
||||
strptr->start = data;
|
||||
|
|
Loading…
Reference in New Issue