diff options
Diffstat (limited to '')
-rw-r--r-- | tests/test_cve_2020_27351.py | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/tests/test_cve_2020_27351.py b/tests/test_cve_2020_27351.py new file mode 100644 index 0000000..1ec1c76 --- /dev/null +++ b/tests/test_cve_2020_27351.py @@ -0,0 +1,149 @@ +#!/usr/bin/python +# +# Copyright (C) 2020 Canonical Ltd +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +"""Unit tests for verifying the correctness of DebFile descriptor handling.""" +import os +import sys +import unittest + +from test_all import get_library_dir + +libdir = get_library_dir() +if libdir: + sys.path.insert(0, libdir) +import gc +import subprocess +import tempfile +import warnings + +import apt_inst + + +@unittest.skipIf(not os.path.exists("/proc/self/fd"), "no /proc/self/fd available") +class TestCVE_2020_27351(unittest.TestCase): + """test the debfile""" + + GOOD_DEB = "data/test_debs/utf8-package_1.0-1_all.deb" + + def test_success(self): + """opening package successfully should not leak fd""" + before = os.listdir("/proc/self/fd") + apt_inst.DebFile(self.GOOD_DEB) + after = os.listdir("/proc/self/fd") + self.assertEqual(before, after) + + def test_regression_bug_977000(self): + """opening with a file handle should work correctly""" + with open(self.GOOD_DEB) as good_deb: + apt_inst.DebFile(good_deb).control.extractdata("control") + + def test_regression_bug_977000_2(self): + """file object <-> debfile cycles should be collected by gc.""" + + class Cycle: + def __init__(self, fname): + self.file = open(fname) + self.deb = apt_inst.DebFile(self) + + def fileno(self): + return self.file.fileno() + + before = os.listdir("/proc/self/fd") + Cycle(self.GOOD_DEB).deb.control.extractdata("control") + warnings.filterwarnings("ignore", category=ResourceWarning) + gc.collect() + warnings.resetwarnings() + after = os.listdir("/proc/self/fd") + self.assertEqual(before, after) + + def test_regression_bug_977000_2_ar(self): + """file object <-> debfile cycles should be collected by gc.""" + + class Cycle: + def __init__(self, fname): + self.file = open(fname) + self.deb = apt_inst.ArArchive(self) + + def fileno(self): + return self.file.fileno() + + before = os.listdir("/proc/self/fd") + Cycle(self.GOOD_DEB).deb.gettar("control.tar.gz", "gzip").extractdata("control") + warnings.filterwarnings("ignore", category=ResourceWarning) + gc.collect() + warnings.resetwarnings() + after = os.listdir("/proc/self/fd") + self.assertEqual(before, after) + + def test_success_a_member(self): + """fd should be kept around as long as a tarfile member""" + before = os.listdir("/proc/self/fd") + data = apt_inst.DebFile(self.GOOD_DEB).data + after = os.listdir("/proc/self/fd") + self.assertEqual(len(before), len(after) - 1) + del data + after = os.listdir("/proc/self/fd") + self.assertEqual(before, after) + + def _create_deb_without(self, member): + temp = tempfile.NamedTemporaryFile(mode="wb") + try: + with open(self.GOOD_DEB, "rb") as deb: + temp.write(deb.read()) + temp.flush() + subprocess.check_call(["ar", "d", temp.name, member]) + return temp + except Exception as e: + temp.close() + raise e + + def test_nocontrol(self): + """opening package without control.tar.gz should not leak fd""" + before = os.listdir("/proc/self/fd") + with self._create_deb_without("control.tar.gz") as temp: + try: + apt_inst.DebFile(temp.name) + except SystemError as e: + self.assertIn("control.tar", str(e)) + else: + self.fail("Did not raise an exception") + + after = os.listdir("/proc/self/fd") + self.assertEqual(before, after) + + def test_nodata(self): + """opening package without data.tar.gz should not leak fd""" + before = os.listdir("/proc/self/fd") + with self._create_deb_without("data.tar.gz") as temp: + try: + apt_inst.DebFile(temp.name) + except SystemError as e: + self.assertIn("data.tar", str(e)) + else: + self.fail("Did not raise an exception") + + after = os.listdir("/proc/self/fd") + self.assertEqual(before, after) + + def test_no_debian_binary(self): + """opening package without debian-binary should not leak fd""" + before = os.listdir("/proc/self/fd") + with self._create_deb_without("debian-binary") as temp: + try: + apt_inst.DebFile(temp.name) + except SystemError as e: + self.assertIn("missing debian-binary", str(e)) + else: + self.fail("Did not raise an exception") + + after = os.listdir("/proc/self/fd") + self.assertEqual(before, after) + + +if __name__ == "__main__": + # logging.basicConfig(level=logging.DEBUG) + unittest.main() |