Skip to content

mv: fail closed when recreating a cross-device directory destination - #13627

Open
sylvestre wants to merge 1 commit into
uutils:mainfrom
sylvestre:mv-cross-device-dir-fail-closed
Open

mv: fail closed when recreating a cross-device directory destination#13627
sylvestre wants to merge 1 commit into
uutils:mainfrom
sylvestre:mv-cross-device-dir-fail-closed

Conversation

@sylvestre

Copy link
Copy Markdown
Contributor

The EXDEV directory fallback removes the destination, then recreates it with create_dir_all. create_dir_all treats an existing symlink-to-directory as success, so anything planted at the path in the gap redirects the entire moved tree through the link, outside the destination.

@github-actions

Copy link
Copy Markdown

GNU testsuite comparison:

Skip an intermittent issue tests/tail/symlink (fails in this run but passes in the 'main' branch)
Skipping an intermittent issue tests/cut/bounded-memory (passes in this run but fails in the 'main' branch)
Skipping an intermittent issue tests/date/resolution (passes in this run but fails in the 'main' branch)
Skipping an intermittent issue tests/tail/retry (passes in this run but fails in the 'main' branch)
Skip an intermittent issue tests/tail/tail-n0f (was skipped on 'main', now failing)

The EXDEV directory fallback removes the destination, then recreates it with
create_dir_all. create_dir_all treats an existing symlink-to-directory as
success, so anything planted at the path in the gap redirects the entire moved
tree through the link, outside the destination.

Measured with a tight symlink() loop (which only succeeds while the path is
absent, i.e. exactly in that gap), 30 rounds of a cross-device
`mv -T srcdir dest`:

  uutils before   30/30 rounds wrote the source files inside the off-tree victim
  uutils after     0/30
  GNU 9.10         0/30

Use create_dir instead, at the top-level destination and for each subdirectory,
so a path that reappeared is refused with EEXIST rather than followed. Normal
cross-device moves are unaffected: dest-absent, into-existing-dir, and -T onto
an existing empty dir all still behave as before and match GNU.
@sylvestre
sylvestre force-pushed the mv-cross-device-dir-fail-closed branch from c801766 to 42bc8b2 Compare July 29, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant