From 8ca438636682b90de807dd1c46ad18cfab950c4b Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 4 Jan 2019 12:23:14 +0100 Subject: [PATCH] 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. --- stream/stream_libarchive.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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];