Skip to content

server: do not let SSH_FXP_RENAME replace an existing file - #704

Merged
puellanivis merged 1 commit into
pkg:masterfrom
likitha011:rename-no-overwrite
Oct 31, 2026
Merged

puellanivis merged 1 commit into
pkg:masterfrom
likitha011:rename-no-overwrite

Conversation

@likitha011

Copy link
Copy Markdown
Contributor

Repro: against the Go Server, client.Rename(old, new) where new already exists returns OK and new now holds the contents of old. OpenSSH's sftp-server answers the same request with SSH_FX_FAILURE and leaves new untouched.
Cause: handlePacket passed SSH_FXP_RENAME straight to os.Rename, which replaces its target. The v3 draft makes RENAME onto an existing name an error, InMemHandler and TestRequestRename already enforce that for the request server, and Client.PosixRename is documented as the form that replaces, so a client using RENAME as a no-clobber step (upload to a temporary name and rename into place, or rename as a lock between two writers) lost the existing file against this server.
Fix: handle the packet in an sshFxpRenamePacket.respond that refuses with EEXIST when newpath exists, as OpenSSH does, and leaves posix-rename@openssh.com overwriting. Adds TestRenameDoesNotOverwrite, which fails on the current server and passes against OpenSSH's sftp-server. make integration and make integration_w_race pass locally on macOS with Go 1.26.10.

The os-backed Server handled SSH_FXP_RENAME with a bare os.Rename, which
replaces newpath when it already exists. The SFTP v3 draft makes that an
error, OpenSSH's sftp-server refuses it with SSH_FX_FAILURE, and the
request server's InMemHandler already enforces it, so a client relying on
RENAME to never clobber (upload to a temporary name and rename into
place, or rename as a lock between two writers) silently lost the
existing file against this server.

Refuse the request when newpath exists. posix-rename@openssh.com keeps
its overwriting behaviour.
@puellanivis
puellanivis merged commit 915d66c into pkg:master Oct 31, 2026
4 checks passed
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.

2 participants