A source like [-oProxyCommand=CMD]:/path passes the bracket-parsing
check in find_base_path() and ends up as -oProxyCommand=CMD in the
ssh argv. When sftp_server is a path, ssh gets a destination argument
and executes the injected ProxyCommand before connecting.
Reject hostnames starting with - after bracket stripping, and add --
before the hostname in the ssh command line so positional args can't
be misread as options.
A malicious SFTP server can return symlink targets that the local
kernel VFS resolves outside the mount root, enabling local file reads
or writes through ordinary operations like cp following a symlink.
Add a contain_symlinks option (default on) that rejects absolute
symlink targets and any target containing a `..` component, returning
EPERM. Users who need legacy pass-through for trusted servers can opt
out with -o no_contain_symlinks.
The check is purely lexical and deliberately strict: in an adversarial
filesystem the server controls intermediate path components, so any
non-`..` component could be a symlink anywhere, making lexical depth
tracking unreliable. Rejecting absolute and any `..` is the simplest
rule that is provably complete against the threat model.
transform_symlinks composes poorly with containment because transformed
results often contain `..`; a warning is emitted when both are enabled.
Tests cover default-on containment (readlink + open/stat traversal),
opt-out behavior, transform_symlinks interaction (both arms), and
option precedence.
sshfs_release looked up the conntab entry by path, but sshfs_rename
moves that entry to the new path. Closing the original handle after a
rename can miss the entry and dereference NULL.
Store the conntab_entry pointer on sshfs_file and use it for release
and open-failure cleanup. Add a regression test for open -> rename -> close.
On macOS, sshfs.blksize is set to 0. The statfs fallback path
(used when the server lacks the statvfs extension) divides by
f_frsize, which inherits that zero. Use 4096 as the default.
Some macOS specific features require FUSE API modifications and
extensions that break compatibility with the vanilla FUSE API. Setting
the compile-time flag FUSE_DARWIN_ENABLE_EXTENSIONS to 0, when building
a file system, disables those API extensions. By default, the macOS
specific API modifications and extensions are enabled.
macFUSE will create the mounpoint (in case it does not exist) before
mounting the volume. This allows unprivileged users to mount volumes
under /Volumes.
Windows native OpenSSH has alternative behavior for standard I/O
descriptors, which can be selected through the OPENSSH_STDIO_MODE
environement variable. Setting it to "nonsock" is required for
sshfs compatibility.
See https://github.com/PowerShell/openssh-portable/pull/759
for details.
Uncached and cached results for readdir were inconsistent -- the former
returned correct stat info for directory entries while the latter
didn't. That's because only names of entries were saved in cache without
stat info. In turn this leads to issues like
https://github.com/junegunn/fzf/issues/3832 since directory traversal
library (https://github.com/charlievieth/fastwalk in this case) relies
on proper stat info returned by readdir. Hence when unchached result was
returned it gave proper outcome, while with cached result it was wrong.
Cache stat info next to entry name to fix the issue. While file
attributes are saved in cache already, they use full path as key. To
avoid potentially plenty of allocations, string copying and cache
lookups to get each attr, let's keep a copy of stat struct independently
to be on the fast path.
"sshfs -o vsock=CID:PORT" will cause sshfs to connect directly to the
given vsock, bypassing ssh, and allowing high performance sshfs mounts
of a VM guest.
Added a secondary check so if a mkdir request fails with EPERM an access request will be tried - returning EEXIST if the access was successful. This matches the correct behaviour expected by applications such as git.
Co-authored-by: Peter Belm <peter.belm@dataalchemist.co.uk>
If ssh is configured to use "Match exec" and the previous working
directory is the mount point, then the shell (bash) hangs calling
stat() on OLDPWD.
Unset OLDPWD so that this doesn't happen.
Fixes#206.
The -o max_conns=N option causes multiple SSH processes and response processing threads to
be created. This means that e.g. reading a large file no longer blocks all access to the
filesystem.
The connection is chosen by checking the per-connection statistics:
1. Choose connection with least outstanding requests; if it's a tie,
2. choose connection with least directory handles; if it's a tie,
3. choose connection with least file handles; if it's a tie,
4. choose connection which has already been established.
The implementation assumes that the max_conns values will be small; it
uses linear search.
Example benchmark:
With single connection:
$ sshfs -o max_conns=1,workaround=nobuflimit ebox: mnt
$ cat mnt/tmp/bigfile > /dev/null &
$ time find mnt > /dev/null
real 1m50.432s
user 0m0.133s
sys 0m0.467s
With multiple connections:
$ ~/in-progress/sshfs/build/sshfs -o max_conns=5,workaround=nobuflimit ebox: mnt
$ cat mnt/tmp/bigfile > /dev/null &
$ time find mnt > /dev/null
real 1m15.338s
user 0m0.142s
sys 0m0.491s
This feature was implemented to large extend by Timo Savola <timo.savola@iki.fi>. Thanks
to CEA.fr for sponsoring the remaining work to complete this feature and integrate it into
SSHFS!
Variables of this kind are created in sshfs_open_common() and freed
in sshfs_release(). Since sshfs_release() calls sshfs_flush(), there
can be no pending write requests before at the time of freeing, so
there is no need for reference counting.
* Use logical not for booleans
Fixes a gcc 7.4.0 complaint:
sshfs.c:1743:28: warning: ‘~’ on a boolean expression [-Wbool-operation]
sshfs.c:1743:28: note: did you mean to use logical not?
* strdup argument to keep it alive after function return
Fixes gcc 7.4.0 complaint:
sshfs.c: In function ‘sshfs_opt_proc’:
sshfs.c:3488:50: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
The standard header for the poll(3) interface is poll.h[0]. This prevents
a warning when building with musl libc:
In file included from sshfs.c:44:
/usr/include/sys/poll.h:1:2: warning: #warning redirecting incorrect #include <sys/poll.h> to <poll.h> [-Wcpp]
#warning redirecting incorrect #include <sys/poll.h> to <poll.h>
^~~~~~~
[0] https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/poll.h.html
When using the "ssh_command" option, commands with multiple spaces in a
row will not be properly parsed. Example:
Properly parsed:
ssh_command = "ssh -o IdentityFile=~/.ssh/id_rsa"
Improperly parsed:
ssh_command = "ssh -o IdentityFile=~/.ssh/id_rsa"
This commit changes the ssh_command parsing logic so that both of the
above examples are considered valid and properly handled.
Fixes: #114.
The current definition of the clean_req() function produces a compiler
warning as it expects 2 parameters but GHRFunc expects 3. This commit
resolves issue #157.
The manpage says that -o idmap=user maps the UID and GID, but it
apparently only mapped the UID. The code was in place to map the GID as
well, but it was hidden behind #ifdef __APPLE__. This commit removes
those #ifdefs, and in a couple of cases the code inside an #else, to
make the option behave as documented.
In libfuse<3, when `fstat_workaround` was true, that meant to always
use the `path` argument to resolve fgetattr instead of the supplied
handle. Before this change, the logic was interpreting
`fstat_workaround` to not use the `path` argument when it was
true. This change reverts to the libfuse<3 behavior.
As of kernel 4.14, the FUSE module's + writeback implementation is not
compatible with network filesystems, and there are no imminent plans
to change that.
For more details, see
https://marc.info/?l=fuse-devel&m=150592103107662&w=2 or
As a consequence, the -o unreliable_append option has become obsolete
as well.
Fixes: #93Fixes: #88Fixes: #81
The st_blksize value of struct stat represents the optimal block size
for file I/O operations. FUSE for macOS will use this value when
preforming read or write operations on the file. The smaller st_blksize
is the more context switches are required to complete the operation.
Setting st_blksize to 0 results in FUSE for macOS falling back to the
global I/O size, that can be specified through the "-o iosize=..."
mount-time option.
Fixesosxfuse/osxfuse#389 and osxfuse/sshfs#33
By default volumes are mounted under /Volumes on macOS. Since macOS
10.12 the /Volumes directory is root-owned. In order to allow non-
privileged users to mount FUSE volumes under /Volumes FUSE will create
non-existent mount points automatically.
Fixesosxfuse/sshfs#27
This commit enables the use of readdir() instead of getdir(). It also
completely disables the cache and the nullpath_ok feature. This will
be fixed in the next commits.
It is unclear why G_SLICE_CONFIG_ALWAYS_MALLOC has been set before but
doing so with the latest version of GLib (2.46.2) results in the
following warning:
GLib-CRITICAL **: g_slice_set_config: assertion 'sys_page_size == 0'
failed
This fixes issue osxfuse/sshfs#17
Commit 74bfa3850a allowed sshfs to run
without requiring a non-NULL path argument for certain
operations. This was erroneous in the case of using certain
workarounds.
Before FUSE 2.9, FUSE had to emulate unlink() if a file was still open
via renaming to a hidden file. This was due to the requirement that a
valid "path" argument must be submitted for many FUSE operations. FUSE
2.9 introduced the flag_nullpath_ok and flag_nopath flags that allow a
FUSE file system to signal to FUSE that the "path" argument may be NULL
in certain operations.
sshfs doesn't require paths if the cache isn't used so communicate
that information to the FUSE layer.
This commit restores the FAQ file present in sshfs versions up to 2.5.
Changes since the version in the 2.5 release:
- Remove most wiki markup
- Edit question about bug reports to point to the Github issue tracker
- Remove unanswered questions
- Minor formatting
Allow the user to customize the cache regular and minimum clean intervals
as flags via the new cache_clean_interval and cache_min_clean_interval
options.
While doing this, rename the internal variables and constants to suffix
them with their unit (seconds).
Document the strage-looking symbol interposition that is necessary for the
OS X case.
While doing this, homogenize the code to do the real connect call for both
the Linux and OS X cases into a helper function. This logic is generic
and should not be replicated into various OS-specific cases.
Revision b4023a19 added an mlock call to ensure the sshfs password is kept
in memory, but did so only for OS X. This is a good idea in general, so
let's remove the condition.
Revision b4023a19dd, which imported the
MacFUSE-specific sshfs fixes into osxfuse-sshfs, added a lock to handle
the refs reference counter of the sshfs_file structure. However, this
lock was only added for OS X, which is a very strange thing to do.
One may think that this was only because MacFUSE 2.2 had some semantics
that differed from regular FUSE, and that would have been quite stupid
for compatibility reasons. A few simple tests show no issues after
removing this lock, so let's keep it out for now. If things break, we
know what to look at.
Move the logic to determine which values to stick into the manual page
to the configure script and replace the logic to build the sshfs.1
manual page with sed instead of abusing cpp.
I'm not using AC_OUTPUT here because this macro is typically used to
generate support build files. Final artifacts of the build should, in
general, be built by the Makefile itself.
When defining a -I flag to point into the source directory, we should
prefix the directory with ${srcdir} so that it can be found when the
build is configured to use a build directory that differs from the
source directory.
This fixes "make distcheck".
Makefile.am always sets LIBDIR in CPPFLAGS. There is no need for sshfs.c
to redefine it to a bogus value when not present, and much less to only
do so for the Darwin case only.
cache_enabled leaked the cache.on setting from the cache module abstraction
back into sshfs, and it only did so for the Darwin case.
This hack was being used to avoid calling cache_add_attr and cache_invalidate
when the cache was disabled... but these two functions already do nothing when
in that case: there is no need to do a second check in the caller.
* Fix dependencies of the sshfs.1 target to actually specify sshfs.1.in as a
source.
* Ensure that failures during the generation of sshfs.1 do not result in a
potentially bogus manpage by first outputting the contents to a temporary
file unknown to the Makefile rule and then replacing the target file once
all is known to be OK.
* Use $(AM_V_GEN) in the command to respect automake's silent rules.
Operating system names are not architectures; therefore, rename the arch
variable to osname to better represent its contents.
While doing this, drop a bunch of unused values from the osname.
Pull in all changes from osxfuse's fork of sshfs into libfuse's sshfs.
There need not be two different copies of this codebase, particularly
because libfuse's version is already autoconf-ified and can support
multiple platforms.
The merge is mostly clean with just a few manual edits to resolve
conflicts.
Up to now, the Changelog has essentially been a (manually maintained)
copy of the git commit history. This doesn't seem to have any point
other than following the GNU coding standards. I believe it's much
better to use the Changelog to summarize the release-to-release
changes that are most important for users (as was done in the NEWS
file until now).
sshfs-fuse always returned 0 in access(file, X_OK) calls, causing nautilus
to prompt "Do you want to run "login.defs", or display its contents?" for
text files that were not executable.
Reported by: Alkis Georgopoulos
Accessing directories with many (several thousand) files over sshfs is
slow, because most SFTP server implementations only send a fixed amount
of entries per READDIR command (e.g. OpenSSH SFTP: 100 entries). This
patch implements sending several READDIR commands in parallel, in order
to speed up directory listing in these cases.
An option (sync_readdir) is also added so that users can easily switch
on the old behaviour.
The performance improvement is astonishing. Accessing a directory with
30k files in from a remote server that has a RTT of 15ms via OpenSSH
SFTP:
Synchronous readdir:
$ ./sshfs -o sync_readdir host:/tmp /mnt/temp
$ time "ls" -1 /mnt/temp/test | wc -l
30000
"ls" -1 /mnt/temp/test 0.07s user 0.01s system 1% cpu 6.928 total
Asynchronous readdir:
$ ./sshfs host:/tmp /mnt/temp
$ time "ls" -1 /mnt/temp/test | wc -l
30000
"ls" -1 /mnt/temp/test 0.07s user 0.01s system 12% cpu 0.605 total
Accessing a directory with 100k files shows even more dramatic
improvement:
Synchronous readdir:
$ ./sshfs -o sync_readdir host:/tmp /mnt/temp
$ time "ls" -1 /mnt/temp/test2 | wc -l
100000
"ls" -1 /mnt/temp/test2 0.67s user 1.22s system 0% cpu 3:31.56 total
Asynchronous readdir:
$ ./sshfs host:/tmp /mnt/temp
$ time "ls" -1 /mnt/temp/test2 | wc -l
100000
"ls" -1 /mnt/temp/test2 0.20s user 0.03s system 14% cpu 1.631 total
This can easily be reproduced by creating a directory on a server and
touching a lot of files in it:
$ mkdir /tmp/test
$ cd /tmp/test
$ for i in $(seq 1 30000); do touch $i; done
Signed-off-by: Alexander Neumann <alexander@bumpern.de>
In the past we relied on libosxfuse including a working unnamed semaphore
implmentation for Mac OS X. This will not be the case in future releases of
OSXFUSE, therefore we need to add our own implementation.
cache.c: In function ‘cache_add_attr’:
cache.c:167:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable]
cache.c: In function ‘cache_add_dir’:
cache.c:188:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable]
cache.c: In function ‘cache_add_link’:
cache.c:212:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable]
cache.c: In function ‘cache_add_attr’:
cache.c:167:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable]
cache.c: In function ‘cache_add_dir’:
cache.c:188:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable]
cache.c: In function ‘cache_add_link’:
cache.c:212:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable]
These options allow you to create a pair of local files, with
username:uid/groupname:gid pairs, one per line. Alternatively, files can
be in standard /etc/passwd / /etc/group format.
The uid/gids are for the remote server, their local counterparts are
looked up with a local getpwnam/getgrnam call. Any stat() calls will
show with the remapped local uid/gid, and any chown() calls will be
remapped back to the remote uid/gid.
Also don't limit the kernel to 64k reads and writes, rather split into
32k sized chunks and send them to the server all at once. This is
more efficient and less demanding from the server.
Reported by Ludovic Courtès. Fix suggested by Niels Möller
These options allow you to create a pair of local files, with
username:uid/groupname:gid pairs, one per line. Alternatively, files can
be in standard /etc/passwd / /etc/group format.
The uid/gids are for the remote server, their local counterparts are
looked up with a local getpwnam/getgrnam call. Any stat() calls will
show with the remapped local uid/gid, and any chown() calls will be
remapped back to the remote uid/gid.
Also don't limit the kernel to 64k reads and writes, rather split into
32k sized chunks and send them to the server all at once. This is
more efficient and less demanding from the server.
Reported by Ludovic Courtès. Fix suggested by Niels Möller
file as the mountpoint, i.e. both are directories or both are
non-directories (debian bug #535343). Reported by Greg Kochanski
* Allow mounting a single non-directory from the server
SSHFS does not have any active, regular contributors or developers. The current maintainer continues to apply pull requests and tries to make regular releases, but unfortunately has no capacity to do any development beyond addressing high-impact issues. When reporting bugs, please understand that unless you are including a pull request or are reporting a critical issue, you will probably not get a response.
To prevent the issue tracker from being flooded with issues that no-one is intending to work on, and to give more visibility to critical issues that users should be aware of and that most urgently need attention, I will also close most bug reports once they've been inactive for a while.
Please note that this isn't meant to imply that you haven't found a bug - you most likely have and I'm grateful that you took the time to report it. Unfortunately, SSHFS is a purely volunteer driven project,
and at the moment there simply aren't any volunteers.
* Added new maintainer: abhinavagarwal07 Abhinav Agarwal
* Fixed critical vulnerability CVE-2026-47187 - Symlink Escape: Rogue SFTP Server to Local File Read/Write), credit to abhinavagarwal07
* New -o contain_symlinks and -o no_contain_symlinks to control symlink containment behavior
* Fixed high severity vulnerability CVE-2026-48711 - Improper Neutralization of Argument Delimiters in a Command ('Argument Injection'), credit to abhinavagarwal07
* Fixed null-deref warning in tokenize_on_space, promote strict-warnings to required
* Added a number of tests in CI, including rename, chmod, fsync, statvfs values, error paths, option coverage
* Fixed malformed SFTP reply handling
* Hardened Github Actions workflow with SHA pins, permissions, timeouts, and dependabot
Release 3.7.5 (2025-11-11)
--------------------------
* New maintainers added
* Main documentation updates to using Markdown
* Updated Windows and macOS support
* Added IPv6 support in -o directport
* Added -o vsock option
* Minor bugfixes
Release 3.7.3 (2022-05-26)
--------------------------
* Minor bugfixes.
* This is the last release from the current maintainer. SSHFS is now no longer maintained
or developed. Github issue tracking and pull requests have therefore been disabled. The
mailing list (see below) is still available for use.
If you would like to take over this project, you are welcome to do so. Please fork it
and develop the fork for a while. Once there has been 6 months of reasonable activity,
please contact Nikolaus@rath.org and I'll be happy to give you ownership of this
repository or replace with a pointer to the fork.
Release 3.7.2 (2021-06-08)
--------------------------
* Added a secondary check so if a mkdir request fails with EPERM an access request will be
tried - returning EEXIST if the access was successful.
SSHFS allows you to mount a remote filesystem using SFTP. Most SSH
servers support and enable this SFTP access by default, so SSHFS is
very simple to use - there's nothing to do on the server-side.
## Development Status
SSHFS is shipped by all major Linux distributions and has been in
production use across a wide range of systems for many years. However,
at present SSHFS does not have any active, regular contributors, and
there are a number of known issues (see the [bugtracker](https://github.com/libfuse/sshfs/issues)).
The current maintainer continues to apply pull requests and makes regular
releases, but unfortunately has no capacity to do any development
beyond addressing high-impact issues. When reporting bugs, please
understand that unless you are including a pull request or are
reporting a critical issue, you will probably not get a response.
## How to use
Once sshfs is installed (see next section) running it is very simple:
```
sshfs [user@]hostname:[directory] mountpoint
```
It is recommended to run SSHFS as regular user (not as root). For
this to work the mountpoint must be owned by the user. If username is
omitted SSHFS will use the local username. If the directory is
omitted, SSHFS will mount the (remote) home directory. If you need to
enter a password sshfs will ask for it (actually it just runs ssh
which asks for the password if needed).
Also many ssh options can be specified (see the manual pages for
*sftp(1)* and *ssh_config(5)*), including the remote port number
(`-oport=PORT`)
To unmount the filesystem:
```
fusermount -u mountpoint
```
On BSD and macOS, to unmount the filesystem:
```
umount mountpoint
```
### Bypassing SSH
#### Using directport
Using direct connections to sftp-server to bypass SSH for performance is also possible. To do this, start a network service using sftp-server (part of OpenSSH) on a server, then connect directly using `-o directport=PORT` option.
Note that this is insecure as connection will happen without encryption. Only use this on localhost or trusted networks. This option is sometimes used by other projects to mount folders inside VMs.
Similarly to above, Linux [vsock](https://man7.org/linux/man-pages/man7/vsock.7.html) can be used to connect directly to sockets within VMs using `-o vsock=CID:PORT`.
# Don't call this script. It is used internally by the Meson
# build system. Thank you for your cooperation.
#
set -e
bindir="$2"
sbindir="$1"
prefix="${MESON_INSTALL_DESTDIR_PREFIX}"
mkdir -p "${prefix}/${sbindir}"
ln -svf --relative "${prefix}/${bindir}/sshfs"\
"${prefix}/${sbindir}/mount.sshfs"
ln -svf --relative "${prefix}/${bindir}/sshfs"\
"${prefix}/${sbindir}/mount.fuse.sshfs"
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.