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.
This commit is contained in:
wm4 2019-01-04 12:23:14 +01:00
parent e5c1cf2e3e
commit 8ca4386366
1 changed files with 3 additions and 1 deletions

View File

@ -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];