Rework client to prevent after-Close usage, and support perm at Open#574
Conversation
| // FileMode returns the Mode SFTP file attribute converted to an os.FileMode | ||
| func (fs *FileStat) FileMode() os.FileMode { | ||
| return toFileMode(fs.Mode) | ||
| } |
There was a problem hiding this comment.
This was located in a different file, which is a little weird, since it operates on FileStat.
|
|
||
| mu sync.Mutex | ||
| mu sync.RWMutex | ||
| handle string |
There was a problem hiding this comment.
handle is now protected by mutex.
| Path: tmppath, | ||
| Pflags: pflags, | ||
| }) | ||
| id2 := client.nextID() |
There was a problem hiding this comment.
move this, so we have the potential for a tighter race possibility.
…ce to alter atime or mtime
| // so we need to also unconditionally mark this handle as invalid. | ||
|
|
||
| handle := f.handle | ||
| f.handle = "" |
There was a problem hiding this comment.
This is the meat of the fix for double closes.
There was a problem hiding this comment.
The design principle here is that the handle on the server side may be reused after a Close, and thus we should synchronize around invalidating the handle in our struct in order to indicate this closed status.
This way, one cannot “accidentally” also use-after-close something like Read or Write as well.
| case 8: | ||
| // words[8] can either have full path or just the filename | ||
| bad = !strings.HasSuffix(opWord, "/"+goWord) |
There was a problem hiding this comment.
🤷♀️ I don’t know what is up about the macOS I’m doing dev on, but openssh is dumping full paths, while our go server is not.
But like, this test was passing for other machines, right? So, ¿ 😕 ?
| if f.handle == "" { | ||
| return 0, os.ErrClosed | ||
| } | ||
| handle := f.handle // need a local copy to prevent aberrent race detection |
There was a problem hiding this comment.
Since we use f.handle in a sub-goroutine, the access is caught by the race detector as being performed “outside of” the lock that we’re holding in this primary goroutine, which triggers the race condition detector.
So, we need to, in this primary goroutine, extract the f.handle value into a local variable, which we can then access through closure in the sub goroutine. We’re safe to use a copy, because it cannot be updated as long as we’re holding either the read or write lock… which is why it’s an aberrent race detection. It just cannot tell that this sub goroutine’s lifetime is guaranteed to be limited by the primary goroutine.
| attr, _ := unmarshalAttrs(data) | ||
| return fileInfoFromStat(attr, path.Base(p)), nil | ||
| attr, _, err := unmarshalAttrs(data) | ||
| return fileInfoFromStat(attr, path.Base(p)), err |
There was a problem hiding this comment.
Should prefer returning either a valid left or valid right, not both.
| // so we need to also unconditionally mark this handle as invalid. | ||
|
|
||
| handle := f.handle | ||
| f.handle = "" |
There was a problem hiding this comment.
The design principle here is that the handle on the server side may be reused after a Close, and thus we should synchronize around invalidating the handle in our struct in order to indicate this closed status.
This way, one cannot “accidentally” also use-after-close something like Read or Write as well.
|
Alright, I feel this is pretty solid now. I’ll be merging it shortly. |
I plan to do some testing this weekend, but I'm sure I won't find anything wrong. Sounds like a great job, thanks! |
I’ll hold off until Monday then. More broad testing is better than the very narrow testing that I’ve done so far. |
|
LGTM, since we are adding support for perm at Open for the server implementation maybe we can also add them in |
|
Adding support in |
Thank you! |
(#16068) Fix for github.com/pkg/sftp#574 was merged in pkg/sftp@46d90e3 so we can remove this replace directive now.
Two things in this:
File.handleafter aClosewhich can then be used to ensure that there is no use-after-close issue: close file double time sometimes cause copy problem wh #572Clientcode, we can now easily implement the PR changes in: fix: add support for attrs insshFxpOpenPacketforServer#567