]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.10] gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 9 May 2023 16:46:47 +0000 (09:46 -0700)
committerGitHub <noreply@github.com>
Tue, 9 May 2023 16:46:47 +0000 (09:46 -0700)
gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096)

* Fix directory traversal security flaw in uu.decode()
* also check absolute paths and os.altsep
* Add a regression test.

---------

(cherry picked from commit 0aeda297931820436a50b78f4f7f0597274b5df4)

 [Google]

Co-authored-by: Sam Carroll <70000253+samcarroll42@users.noreply.github.com>
Lib/test/test_uu.py
Lib/uu.py [changed mode: 0755->0644]
Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst [new file with mode: 0644]

index 753b31eef0d3ba6d61b1a0da4f8ae10c58474875..8cc1c074850b6b83cc393ee02ff7f190c52952fa 100644 (file)
@@ -145,6 +145,34 @@ class UUTest(unittest.TestCase):
         uu.encode(inp, out, filename)
         self.assertIn(safefilename, out.getvalue())
 
+    def test_no_directory_traversal(self):
+        relative_bad = b"""\
+begin 644 ../../../../../../../../tmp/test1
+$86)C"@``
+`
+end
+"""
+        with self.assertRaisesRegex(uu.Error, 'directory'):
+            uu.decode(io.BytesIO(relative_bad))
+        if os.altsep:
+            relative_bad_bs = relative_bad.replace(b'/', b'\\')
+            with self.assertRaisesRegex(uu.Error, 'directory'):
+                uu.decode(io.BytesIO(relative_bad_bs))
+
+        absolute_bad = b"""\
+begin 644 /tmp/test2
+$86)C"@``
+`
+end
+"""
+        with self.assertRaisesRegex(uu.Error, 'directory'):
+            uu.decode(io.BytesIO(absolute_bad))
+        if os.altsep:
+            absolute_bad_bs = absolute_bad.replace(b'/', b'\\')
+            with self.assertRaisesRegex(uu.Error, 'directory'):
+                uu.decode(io.BytesIO(absolute_bad_bs))
+
+
 class UUStdIOTest(unittest.TestCase):
 
     def setUp(self):
old mode 100755 (executable)
new mode 100644 (file)
index 9f1f37f..9fe252a
--- a/Lib/uu.py
+++ b/Lib/uu.py
@@ -130,7 +130,14 @@ def decode(in_file, out_file=None, mode=None, quiet=False):
             # If the filename isn't ASCII, what's up with that?!?
             out_file = hdrfields[2].rstrip(b' \t\r\n\f').decode("ascii")
             if os.path.exists(out_file):
-                raise Error('Cannot overwrite existing file: %s' % out_file)
+                raise Error(f'Cannot overwrite existing file: {out_file}')
+            if (out_file.startswith(os.sep) or
+                f'..{os.sep}' in out_file or (
+                    os.altsep and
+                    (out_file.startswith(os.altsep) or
+                     f'..{os.altsep}' in out_file))
+               ):
+                raise Error(f'Refusing to write to {out_file} due to directory traversal')
         if mode is None:
             mode = int(hdrfields[1], 8)
         #
diff --git a/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst
new file mode 100644 (file)
index 0000000..b7002e8
--- /dev/null
@@ -0,0 +1,2 @@
+Fixed a security in flaw in :func:`uu.decode` that could allow for
+directory traversal based on the input if no ``out_file`` was specified.