From 518602ab11578d74df1f141fe342e4082ac99875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gust=C3=A4bel?= Date: Mon, 6 Jul 2015 09:23:04 +0200 Subject: Issue #24259: tarfile now raises a ReadError if an archive is truncated inside a data segment. --- Lib/tarfile.py | 17 ++++++++++++++--- Lib/test/test_tarfile.py | 24 ++++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py index d7c1500..66e5393 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -744,12 +744,18 @@ class _FileInFile(object): else: return self.readsparse(size) + def __read(self, size): + buf = self.fileobj.read(size) + if len(buf) != size: + raise ReadError("unexpected end of data") + return buf + def readnormal(self, size): """Read operation for regular files. """ self.fileobj.seek(self.offset + self.position) self.position += size - return self.fileobj.read(size) + return self.__read(size) def readsparse(self, size): """Read operation for sparse files. @@ -777,7 +783,7 @@ class _FileInFile(object): realpos = section.realpos + self.position - section.offset self.fileobj.seek(self.offset + realpos) self.position += size - return self.fileobj.read(size) + return self.__read(size) else: self.position += size return NUL * size @@ -2336,8 +2342,13 @@ class TarFile(object): self.firstmember = None return m + # Advance the file pointer. + if self.offset != self.fileobj.tell(): + self.fileobj.seek(self.offset - 1) + if not self.fileobj.read(1): + raise ReadError("unexpected end of data") + # Read the next block. - self.fileobj.seek(self.offset) tarinfo = None while True: try: diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index a92d371..a72c37b 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -285,6 +285,30 @@ class CommonReadTest(ReadTest): "ignore_zeros=True should have skipped the %r-blocks" % char) tar.close() + def test_premature_end_of_archive(self): + for size in (512, 600, 1024, 1200): + with tarfile.open(tmpname, "w:") as tar: + t = tarfile.TarInfo("foo") + t.size = 1024 + tar.addfile(t, StringIO.StringIO("a" * 1024)) + + with open(tmpname, "r+b") as fobj: + fobj.truncate(size) + + with tarfile.open(tmpname) as tar: + with self.assertRaisesRegexp(tarfile.ReadError, "unexpected end of data"): + for t in tar: + pass + + with tarfile.open(tmpname) as tar: + t = tar.next() + + with self.assertRaisesRegexp(tarfile.ReadError, "unexpected end of data"): + tar.extract(t, TEMPDIR) + + with self.assertRaisesRegexp(tarfile.ReadError, "unexpected end of data"): + tar.extractfile(t).read() + class MiscReadTest(CommonReadTest): taropen = tarfile.TarFile.taropen diff --git a/Misc/NEWS b/Misc/NEWS index 3f98a15..0b55665 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,9 @@ Core and Builtins Library ------- +- Issue #24259: tarfile now raises a ReadError if an archive is truncated + inside a data segment. + - Issue #24514: tarfile now tolerates number fields consisting of only whitespace. -- cgit v0.12