]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.15] gh-149835: Use realpath() instead of abspath() in shutil.move() (GH-149986...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sat, 6 Jun 2026 10:29:57 +0000 (12:29 +0200)
committerGitHub <noreply@github.com>
Sat, 6 Jun 2026 10:29:57 +0000 (10:29 +0000)
(cherry picked from commit fab449bddbc4ff03677d49448cf6ea1f9d6a319f)

Co-authored-by: Thomas Kowalski <thom.kowa@gmail.com>
Lib/shutil.py
Lib/test/test_shutil.py
Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst [new file with mode: 0644]

index 45cbe4c855b462b1a6a6fee228443f31157de788..d3ac5dc5c50a734664c21a86b8d47fc258a3e097 100644 (file)
@@ -940,8 +940,8 @@ def move(src, dst, copy_function=copy2):
     return real_dst
 
 def _destinsrc(src, dst):
-    src = os.path.abspath(src)
-    dst = os.path.abspath(dst)
+    src = os.path.realpath(src)
+    dst = os.path.realpath(dst)
     if not src.endswith(os.path.sep):
         src += os.path.sep
     if not dst.endswith(os.path.sep):
index 13a3487382dfcfb589ca6a272576bb27ba89a482..c2485e20a199039fc9c067e1b7b1432bfa744dec 100644 (file)
@@ -2914,6 +2914,23 @@ class TestMove(BaseTest, unittest.TestCase):
         finally:
             os_helper.rmtree(TESTFN)
 
+    @os_helper.skip_unless_symlink
+    def test_destinsrc_symlink_bypass(self):
+        tmp = self.mkdtemp()
+        src = os.path.join(tmp, 'src')
+        os.makedirs(src)
+        # tmp/link -> tmp (one level up)
+        link = os.path.join(tmp, 'link')
+        os.symlink(tmp, link)
+        # raw path: tmp/link/src/sub - no src prefix in string space
+        # real path: tmp/src/sub     - physically inside src
+        dst = os.path.join(link, 'src', 'sub')
+        self.assertTrue(
+            shutil._destinsrc(src, dst),
+            msg='_destinsrc failed to detect dst inside src via symlink '
+                '(dst=%s, src=%s)' % (dst, src),
+        )
+
     @os_helper.skip_unless_symlink
     @mock_rename
     def test_move_file_symlink(self):
diff --git a/Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst b/Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst
new file mode 100644 (file)
index 0000000..20cab73
--- /dev/null
@@ -0,0 +1,3 @@
+:func:`shutil.move` now resolves symlinks via :func:`os.path.realpath`
+when checking whether the destination is inside the source directory,
+preventing a symlink-based bypass of that guard.