summaryrefslogtreecommitdiffstats
path: root/tests/test_cve_2020_27351.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_cve_2020_27351.py')
-rw-r--r--tests/test_cve_2020_27351.py149
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()