libfuse/sshfs

SSHFS always follows symlink when setting inode attributes

baryluk opened this issue · 3 comments

Using sshfs 3.7.1+repack-1 from Debian testing, amd64. Linux 5.10.28-1 (from Debian).

Standard mount settings:

baryluk@foobar:/ on /home/user/foobar type fuse.sshfs (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)

Somehow similar to #112 , but still is present in current version.

(on sshfs mount)
$ ln -s /bin/ls foo
$ ln -s bar b
$ touch zoo
$ ln -s zoo c
$ ls -l
total 20
drwxr-xr-x 1 user user 4096 May  7 17:35 .
drwxr-xr-x 1 user user 4096 May  7 17:28 ..
lrwxrwxrwx 1 user user    7 May  7 17:28 a -> /bin/ls
lrwxrwxrwx 1 user user    3 May  7 17:35 b -> bar
lrwxrwxrwx 1 user user    3 May  7 17:34 c -> zoo
-rw-r--r-- 1 user user    0 May  7 17:34 zoo
$
$ touch -h a
touch: setting times of 'a': Permission denied
$ touch -h b
touch: setting times of 'b': No such file or directory
$ touch -h c
$ 

It looks like sshfs is following symlink, even if it is requested to not do that.

This causes issues for example with dpkg-deb -x unpacking to sshfs file system (it uses tar -x -p -f -, that often does call utimesat on symlinks to absolute paths):

utimensat(AT_FDCWD, "./lib64/ld-linux-x86-64.so.2", [UTIME_OMIT, {tv_sec=1619902566, tv_nsec=0} /* 2021-05-01T20:56:06+0000 */], AT_SYMLINK_NOFOLLOW) = -1 ENOENT (No such file or directory)

Where ./usr/share/doc/libstdc++6 does in fact exist, and is a symlinking point to actually existing file:

$ stat ./lib64/ld-linux-x86-64.so.2
  File: ./lib64/ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.31.so
  Size: 32        	Blocks: 8          IO Block: 4096   symbolic link
Device: 3dh/61d	Inode: 2612        Links: 1
Access: (0777/lrwxrwxrwx)  Uid: ( 1000/    user)   Gid: ( 1000/    user)
Access: 2021-05-07 17:39:23.000000000 +0000
Modify: 2021-05-07 17:39:23.000000000 +0000
Change: 2021-05-07 17:39:23.000000000 +0000
 Birth: -
$ stat /lib/x86_64-linux-gnu/ld-2.31.so
  File: /lib/x86_64-linux-gnu/ld-2.31.so
  Size: 177928    	Blocks: 352        IO Block: 4096   regular file
Device: 1bh/27d	Inode: 17868       Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2021-05-02 08:15:26.000000000 +0000
Modify: 2021-05-01 20:56:06.000000000 +0000
Change: 2021-05-02 08:15:31.488745282 +0000
 Birth: -

However, it is true that the symlink if interpreted from the mountpoint, doesn't exist:

ls: cannot access '/home/user/foobar/lib/x86_64-linux-gnu/ld-2.31.so': No such file or directory

However, it shouldn't matter, because of the AT_SYMLINK_NOFOLLOW flag. And I don't use -o transform_symlinks anyway.

Thanks for the report! Yes, this is a bug, but I am not sure if it can be fixed. SSHFS is using the SETSTAT/FSETSTAT commands of the SFTP protocol to set file attributes. As far as I can tell, there is no flag that would allow to tell the SFTP server to work on symlinks.

That said, SSHFS still uses an ancient revision of the SFTP protocol - this functionality may well be present in more recent versions. Patches are welcome :-).

It can not be done with SETSTAT unfortunately, nor with FSETSTAT.

It is possible to do however using OpenSSH extension: lsetstat@openssh.com. It was added in OpenSSH 8.0, in 2019.

3.7. sftp: Extension request "lsetstat@openssh.com"

This request is like the "setstat" command, but sets file attributes on
symlinks.  It is implemented as a SSH_FXP_EXTENDED request with the
following format:

	uint32		id
	string		"lsetstat@openssh.com"
	string		path
	ATTRS		attrs

See the "setstat" command for more details.

This extension is advertised in the SSH_FXP_VERSION hello with version
"1".

Marking as duplicate of #105