Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
SFTP client failures for large directories #73
If a directory has a large number of files it is possible that the packet returned in response to FXP_READDIR is too large for the client. Common clients (i.e.: OpenSSH sftp client) have a maximum packet size of 256KiB.
The following code can be used to demonstrate the issue.
I'm testing against master (33761e9)
Using standard OpenSSH sftp client (in this case
The output is:
You can tune the size of the directory by changing '100000' in the script. You'll see that if you dial it down low enough the packet will be small enough to go under the SFTP 256KiB limit.
The way to fix this is by getting
Now, a really good question is where does 128 come from, and why is it even approaching correct. The answer is unsatisfying; the latest SFTP draft specification (which coincidentally expired 10 years ago tomorrow) https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13 has little to say about the issue.
Unfortunately the first sentence is fine for read requests, but not for FXP_READDIR. Unlike the underlying kernel system call, FXP_READDIR doesn't allow the client to specify how many records it expects to receive back, so the server simply has to guess, which is of course ridiculous.
Given the broken spec the best we can do is look at common usage. OpenSSH server just hardcodes it to 100 https://github.com/openssh/openssh-portable/blob/master/sftp-server.c#L1072.
The Go implementation picks 128 instead https://github.com/pkg/sftp/blob/master/server.go#L449.
Per the XXX comments in the OpenSSH implementation it would make more sense to track the size of the packet rather than the number of entries (since the entry size is variable), however that complicates the code somewhat, so picking a number of records seems easier.
And, even if you did something based on the packet size, what packet size could you even pick? There is no minimum packet size in the spec that indicates what a client must support, although probably 32KiB is reasonable given the above quote. In that case 128 gives you 256 bytes per record on average to play with, which is probably OK, but really, who knows.
It would probably be ideal to provide a way to configure either the number of records or the minimum buffer size so it can be tuned based on the clients any user may need to support.
Overall, this is a very unsatisfying issue as there isn't really a right answer, but such is life.
Thanks for your detailed analysis, Ben, and for your suggested fix!
Given that there's nothing negotiated on the wire for the maximum SFTP message size (unlike the max supported SSH packet size, which is actually exchanged when a channel is set up), there's no way to be sure what size is "safe", but it still seems worth at least trying to stay under the hardcoded maximum value in the OpenSSH implementation, since that's probably what is at the other end in most cases. If that turns out to not be sufficient, it might be possible to do something based on the identification string in the version the peer sends at startup. I can also look into making this configurable, if that's not good enough.
I'm also torn about whether to go with a max number of bytes or max number of entries, but given that we can't know the "safe" maximum number of bytes, I think a simpler fix like what you suggest here is probably the best answer for now. This could be a problem if a directory contained multiple really long filenames, but given many OSes have limits on filenames of a few hundred bytes, it's pretty unlikely that we'd run into an issue with that with 128 entries per response, especially at the OpenSSH limit of 256 KiB.
I've been making other changes to the SFTP support in the "develop" branch to make it work better on Windows. I'll put this fix in there as well, and roll it into the next release. Thanks again!