summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-01-04 12:23:14 +0100
committerwm4 <wm4@nowhere>2019-09-19 20:37:03 +0200
commit8ca438636682b90de807dd1c46ad18cfab950c4b (patch)
tree039e5837aec0bc9f6eac2256d6756c7e498555c0
parente5c1cf2e3e76deb32532d213d9b6a48a2b7cf242 (diff)
downloadmpv-8ca438636682b90de807dd1c46ad18cfab950c4b.tar.bz2
mpv-8ca438636682b90de807dd1c46ad18cfab950c4b.tar.xz
stream_libarchive: fix another crash with broken rar files
libarchive (sometimes affectionately called libcve) has this annoying behavior that if after a "fatal" error, you do any operation on the archive context other than querying the error and closing the context, you get a free CVE. So we close the archive context in these situations. This can set p->mpa to NULL, so code accessing this field needs to be careful. This was not considered in a certain code path, and a simple truncated .rar file made it crash. Part of the problem was that the file inside the rar was a mkv file, which triggered seeking when the demux_mkv resync code encountered bogus data. This is probably a regression from a relatively recent change to this code (in any case mpv 0.29.1 doesn't crash). Fix this by adding the check. There's also a mechanism to reopen an archive context used to emulate seeking, since most libarchive format handlers don't support this natively. Add a reopen call to the codepath, because obviously it should always be possible to seek back into a "working" area of the file. There is a second bug with this: if reopening fails, we don't adjust the current position back to 0, which in some cases means we accidentally return bogus data to the reader when we shouldn't. Fix this by always resetting the position on reopening.
-rw-r--r--stream/stream_libarchive.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/stream/stream_libarchive.c b/stream/stream_libarchive.c
index ae06efb890..54ebc64b98 100644
--- a/stream/stream_libarchive.c
+++ b/stream/stream_libarchive.c
@@ -361,6 +361,7 @@ static int reopen_archive(stream_t *s)
{
struct priv *p = s->priv;
mp_archive_free(p->mpa);
+ s->pos = 0;
p->mpa = mp_archive_new(s->log, p->src, MP_ARCHIVE_FLAG_UNSAFE);
if (!p->mpa)
return STREAM_ERROR;
@@ -423,9 +424,10 @@ static int archive_entry_seek(stream_t *s, int64_t newpos)
MP_VERBOSE(s, "trying to reopen archive for performing seek\n");
if (reopen_archive(s) < STREAM_OK)
return -1;
- s->pos = 0;
}
if (newpos > s->pos) {
+ if (!p->mpa && reopen_archive(s) < STREAM_OK)
+ return -1;
// For seeking forwards, just keep reading data (there's no libarchive
// skip function either).
char buffer[4096];