ffmpeg/libavformat/rka.c
Michael Niedermayer b3df7ca748
avformat/rka: Fix 1/0 with bps=1
Fixes: division by zero
Fixes: 55940/clusterfuzz-testcase-minimized-ffmpeg_IO_DEMUXER_fuzzer-6333107679920128

The decoder does not support bps=1 and i have no such sample so it is not
known if this duration is correct. Alternatively we could error out on all
bps we currently do not support on the decoder side or not set duration.

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2023-02-22 18:01:51 +01:00

174 lines
4.8 KiB
C

/*
* RKA demuxer
* Copyright (c) 2023 Paul B Mahol
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/dict.h"
#include "libavutil/intreadwrite.h"
#include "apetag.h"
#include "avformat.h"
#include "avio_internal.h"
#include "demux.h"
#include "internal.h"
typedef struct RKAContext {
int total_frames, currentframe;
int frame_size;
int last_frame_size;
} RKAContext;
static int rka_probe(const AVProbeData *p)
{
if (AV_RL32(&p->buf[0]) == MKTAG('R', 'K', 'A', '7') &&
AV_RL32(&p->buf[4]) > 0 &&
AV_RL32(&p->buf[8]) > 0 &&
p->buf[12] > 0 &&
p->buf[12] <= 2 &&
(p->buf[13] == 8 || p->buf[13] == 16) &&
(p->buf[15] & 2) != 0)
return AVPROBE_SCORE_EXTENSION + 30;
return 0;
}
static int rka_read_header(AVFormatContext *s)
{
int64_t nb_samples, size_offset;
RKAContext *c = s->priv_data;
int channels, bps, samplerate;
AVCodecParameters *par;
int64_t framepos;
AVStream *st;
int ret;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
par = st->codecpar;
ret = ff_get_extradata(s, par, s->pb, 16);
if (ret < 0)
return ret;
nb_samples = AV_RL32(par->extradata + 4);
samplerate = AV_RL32(par->extradata + 8);
channels = par->extradata[12];
if (channels == 0)
return AVERROR_INVALIDDATA;
bps = par->extradata[13];
if (bps == 0)
return AVERROR_INVALIDDATA;
size_offset = avio_rl32(s->pb);
framepos = avio_tell(s->pb);
c->frame_size = 131072;
avpriv_set_pts_info(st, 64, 1, samplerate);
st->start_time = 0;
avio_seek(s->pb, size_offset, SEEK_SET);
c->total_frames = (nb_samples + c->frame_size - 1) / c->frame_size;
c->last_frame_size = nb_samples % c->frame_size;
for (int i = 0; i < c->total_frames; i++) {
int r, end = 0;
int64_t size;
if (avio_feof(s->pb))
break;
size = avio_rl24(s->pb);
if (size == 0) {
end = 1;
size = size_offset - framepos;
if (size <= 0)
break;
}
if ((r = av_add_index_entry(st, framepos, (i * 131072LL) / (channels * (bps >> 3)),
size, 0, AVINDEX_KEYFRAME)) < 0)
return r;
framepos += size;
if (end)
break;
}
par->codec_type = AVMEDIA_TYPE_AUDIO;
par->codec_id = AV_CODEC_ID_RKA;
par->ch_layout.nb_channels = channels;
par->sample_rate = samplerate;
par->bits_per_raw_sample = bps;
st->duration = 8LL*nb_samples / (channels * bps);
if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
ff_ape_parse_tag(s);
avio_seek(s->pb, 20, SEEK_SET);
return 0;
}
static int rka_read_packet(AVFormatContext *s, AVPacket *pkt)
{
RKAContext *c = s->priv_data;
AVStream *st = s->streams[0];
FFStream *const sti = ffstream(st);
int size, ret;
if (avio_feof(s->pb))
return AVERROR_EOF;
if (c->currentframe >= sti->nb_index_entries)
return AVERROR_EOF;
size = sti->index_entries[c->currentframe].size;
ret = av_get_packet(s->pb, pkt, size);
pkt->dts = sti->index_entries[c->currentframe++].timestamp;
pkt->duration = c->currentframe == c->total_frames ? c->last_frame_size :
131072;
return ret;
}
static int rka_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
{
RKAContext *c = s->priv_data;
AVStream *st = s->streams[stream_index];
int index = av_index_search_timestamp(st, timestamp, flags);
if (index < 0)
return -1;
if (avio_seek(s->pb, ffstream(st)->index_entries[index].pos, SEEK_SET) < 0)
return -1;
c->currentframe = index;
return 0;
}
const AVInputFormat ff_rka_demuxer = {
.name = "rka",
.long_name = NULL_IF_CONFIG_SMALL("RKA (RK Audio)"),
.priv_data_size = sizeof(RKAContext),
.read_probe = rka_probe,
.read_header = rka_read_header,
.read_packet = rka_read_packet,
.read_seek = rka_read_seek,
.extensions = "rka",
};