summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2023-05-22 10:41:30 (GMT)
committerGitHub <noreply@github.com>2023-05-22 10:41:30 (GMT)
commit3d5dd1eee265ec43dd96d89656c2a1c207dd5815 (patch)
tree2ec0584c1df5acf29810bfd0b51950be31d09ddf
parentb53d0ff4312cc2a67b9c5752844b140c08514648 (diff)
downloadcpython-3d5dd1eee265ec43dd96d89656c2a1c207dd5815.zip
cpython-3d5dd1eee265ec43dd96d89656c2a1c207dd5815.tar.gz
cpython-3d5dd1eee265ec43dd96d89656c2a1c207dd5815.tar.bz2
[3.9] gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096) (#104331)
(cherry picked from commit 0aeda297931820436a50b78f4f7f0597274b5df4) Co-authored-by: Sam Carroll <70000253+samcarroll42@users.noreply.github.com>
-rw-r--r--Lib/test/test_uu.py28
-rw-r--r--[-rwxr-xr-x]Lib/uu.py9
-rw-r--r--Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst2
3 files changed, 38 insertions, 1 deletions
diff --git a/Lib/test/test_uu.py b/Lib/test/test_uu.py
index 4c639b7..410eb8e 100644
--- a/Lib/test/test_uu.py
+++ b/Lib/test/test_uu.py
@@ -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):
diff --git a/Lib/uu.py b/Lib/uu.py
index 9f1f37f..9fe252a 100755..100644
--- 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
index 0000000..b7002e8
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst
@@ -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.