Bug 3036 - Legacy SFTP rename (SSH2_FXP_RENAME) fails for files owned by others
Summary: Legacy SFTP rename (SSH2_FXP_RENAME) fails for files owned by others
Status: CLOSED FIXED
Alias: None
Product: Portable OpenSSH
Classification: Unclassified
Component: sftp-server (show other bugs)
Version: 8.0p1
Hardware: Other Solaris
: P5 normal
Assignee: Assigned to nobody
URL:
Keywords:
Depends on:
Blocks: V_8_1
  Show dependency treegraph
 
Reported: 2019-07-17 00:09 AEST by Peter Harvey
Modified: 2021-04-23 15:09 AEST (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Peter Harvey 2019-07-17 00:09:30 AEST
Legacy SFTP clients are unable to rename (ie move) files owned by others on Solaris and its derivatives.

Steps to reproduce using the undocumented "legacy" flag in SFTP's rename:

-=-=-
Using Solaris 11.4
-=-=-

# pwd
/export/home/jack
# ls -l
total 34
drwxr-xr-x   2 jack     staff          2 Jul 16 11:23 bar
-rw-r--r--   1 root     staff          0 Jul 16 11:23 foo
# sftp jack@localhost
Password:
Connected to jack@localhost.
sftp> ls -l
drwxr-xr-x    2 jack     staff           2 Jul 16 11:23 bar
-rw-r--r--    1 root     staff           0 Jul 16 11:23 foo
sftp> rename foo bar/foo
sftp> rename bar/foo foo
sftp> rename -l foo bar/foo
Couldn't rename file "/export/home/jack/foo" to "/export/home/jack/bar/foo": Permission denied
sftp>

Turning on verbose output we see:

sftp> rename -l foo bar/foo
debug3: Sent message SSH2_FXP_RENAME "/export/home/jack/foo" -> "/export/home/jack/bar/foo"
debug3: SSH2_FXP_STATUS 3
Couldn't rename file "/export/home/jack/foo" to "/export/home/jack/bar/foo": Permission denied
sftp> rename foo bar/foo
debug3: Sent message posix-rename@openssh.com "/export/home/jack/foo" -> "/export/home/jack/bar/foo"
debug3: SSH2_FXP_STATUS 0
sftp>

-=-=-

Older versions of SFTP use the pre-POSIX rename SSH2_FXP_RENAME or SSH_FXP_RENAME. Examples include Solaris's SunSSH and WinSCP.

The problem is caused by the PRIV_FILE_LINK_ANY privilege being dropped:

./sftp-server.c

int
sftp_server_main(int argc, char **argv, struct passwd *user_pw)
{
	[...]

	/* Drop any fine-grained privileges we don't need */
	platform_pledge_sftp_server();

./platform-pledge.c

/*
 * Drop any fine-grained privileges that are not needed for post-startup
 * operation of sftp-server
 */
void
platform_pledge_sftp_server(void)
{
#ifdef USE_SOLARIS_PRIVS
	solaris_drop_privs_pinfo_net_fork_exec();
#endif
}

./openbsd-compat/port-solaris.c

void
solaris_drop_privs_pinfo_net_fork_exec(void)
{
	priv_set_t *pset = NULL, *npset = NULL;

	[...]

	if (priv_addset(npset, PRIV_FILE_CHOWN) != 0 ||
	    priv_addset(npset, PRIV_FILE_DAC_READ) != 0 ||
	    priv_addset(npset, PRIV_FILE_DAC_SEARCH) != 0 ||
	    priv_addset(npset, PRIV_FILE_DAC_WRITE) != 0 ||
	    priv_addset(npset, PRIV_FILE_OWNER) != 0)
		fatal("priv_addset: %s", strerror(errno));

	if (priv_delset(npset, PRIV_FILE_LINK_ANY) != 0 ||

The pre-POSIX rename operation uses link()/unlink(), the comment reads "Race-free rename of regular files". Without PRIV_FILE_LINK_ANY the calls to link() will fail if the effective user ID doesn't match the owner of the file.
Comment 1 Damien Miller 2019-08-30 14:39:05 AEST
The sandboxing code here was written by Alex Wilson (Cc'd) and I'd like their opinion before restoring that particular privilege (I'm not familiar with Solaris' privilege model myself)
Comment 2 Alex Wilson 2019-08-30 15:06:42 AEST
I think adding that particular privilege back in for sftp-server should be fine. I guess I missed this particular semantic of older clients at the time and took out a little too much.

The only user of solaris_drop_privs_pinfo_net_fork_exec() is platform_pledge_sftp_server() at the moment, I believe, so simply changing that function should be fine. The name doesn't make it clear whether FILE_LINK_ANY is in there or not, so I think it'd also be fine not to rename it.
Comment 3 Damien Miller 2019-09-02 10:26:26 AEST
Thanks, I've remove the delset line. This should be fixed in git master and will be in the OpenSSH 8.1 release soon.
Comment 4 Damien Miller 2021-04-23 15:09:42 AEST
closing resolved bugs as of 8.6p1 release