Skip to content

Commit 861e332

Browse files
KowalskiThomasmiss-islington
authored andcommitted
gh-149835: Use realpath() instead of abspath() in shutil.move() (GH-149986)
(cherry picked from commit fab449b) Co-authored-by: Thomas Kowalski <thom.kowa@gmail.com>
1 parent 6a40e1c commit 861e332

3 files changed

Lines changed: 22 additions & 2 deletions

File tree

Lib/shutil.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -878,8 +878,8 @@ def move(src, dst, copy_function=copy2):
878878
return real_dst
879879

880880
def _destinsrc(src, dst):
881-
src = os.path.abspath(src)
882-
dst = os.path.abspath(dst)
881+
src = os.path.realpath(src)
882+
dst = os.path.realpath(dst)
883883
if not src.endswith(os.path.sep):
884884
src += os.path.sep
885885
if not dst.endswith(os.path.sep):

Lib/test/test_shutil.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2891,6 +2891,23 @@ def test_destinsrc_false_positive(self):
28912891
finally:
28922892
os_helper.rmtree(TESTFN)
28932893

2894+
@os_helper.skip_unless_symlink
2895+
def test_destinsrc_symlink_bypass(self):
2896+
tmp = self.mkdtemp()
2897+
src = os.path.join(tmp, 'src')
2898+
os.makedirs(src)
2899+
# tmp/link -> tmp (one level up)
2900+
link = os.path.join(tmp, 'link')
2901+
os.symlink(tmp, link)
2902+
# raw path: tmp/link/src/sub - no src prefix in string space
2903+
# real path: tmp/src/sub - physically inside src
2904+
dst = os.path.join(link, 'src', 'sub')
2905+
self.assertTrue(
2906+
shutil._destinsrc(src, dst),
2907+
msg='_destinsrc failed to detect dst inside src via symlink '
2908+
'(dst=%s, src=%s)' % (dst, src),
2909+
)
2910+
28942911
@os_helper.skip_unless_symlink
28952912
@mock_rename
28962913
def test_move_file_symlink(self):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:func:`shutil.move` now resolves symlinks via :func:`os.path.realpath`
2+
when checking whether the destination is inside the source directory,
3+
preventing a symlink-based bypass of that guard.

0 commit comments

Comments
 (0)