Skip to content

shutil.move can move the dir into itself (with a symlink) #149835

@KowalskiThomas

Description

@KowalskiThomas

Bug report

Bug description:

I recently read this article "bugs that Rust won't catch" and thought I'd check if CPython has similar issues in shutil, I found this.

shutil.move, in the cross-device move case (if os.rename raises OSError), calls _destinsrc(src, dst) to prevent moving a directory into itself, which would cause copytree to recurse infinitely. The guard compares path strings after os.path.abspath, which normalises e.g. . or .., but does not resolve symlinks. A symlink component anywhere in dst could make the string comparison miss, silently bypassing the guard.
(Note that _destinsrc is only called in the cross-device/cross-filesystem fallback path, when os.rename raises OSError and copytree is used instead.)

To fix this, _destinsrc could be updated to use realpath instead of abspath:

def _destinsrc(src, dst):
    src = os.path.realpath(src)
    dst = os.path.realpath(dst)
    # ...

I have this branch which updates it (with a regression test added).

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions