fix: do not dereference nil attributes in the example Filecmd - #662
Open
labeedahmad-debug wants to merge 1 commit into
Open
labeedahmad-debug wants to merge 1 commit into
labeedahmad-debug wants to merge 1 commit into
Conversation
Request.Attributes returns nil when the attribute blob does not hold every field its flags promise; that behaviour is deliberate (pkg#325, pkg#328). The example server dereferenced it anyway, so a SETSTAT that sets SSH_FILEXFER_ATTR_SIZE with fewer than eight bytes of attributes panicked the packet worker and ended the process. Servers written from the example inherit that. The example now answers SSH_FX_BAD_MESSAGE instead, and the doc comment on Attributes says a nil result is possible, so callers know to check it. Fixes pkg#661 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
puellanivis
reviewed
Sep 21, 2026
puellanivis
left a comment
Collaborator
There was a problem hiding this comment.
Please do not use Co-Authored-By for an LLM. Legally, an LLM cannot be an author in any copyright jurisdiction that I am aware of. Instead, it is suggested to use Assisted-by:: https://docs.kernel.org/process/coding-assistants.html#attribution
Comment on lines
+12
to
+17
| fs := InMemHandler().FileCmd.(*root) | ||
|
|
||
| _, err := fs.Filewrite(&Request{Method: "Put", Filepath: "/foo", Flags: sshFxfWrite | sshFxfCreat}) | ||
| require.NoError(t, err) | ||
|
|
||
| err = fs.Filecmd(&Request{ |
Collaborator
There was a problem hiding this comment.
There is no reason to type assert out to the concrete *root type here. We can just use the FilePut and ̀ FileCmd` fields as they’re designed to be used:
Suggested change
| fs := InMemHandler().FileCmd.(*root) | |
| _, err := fs.Filewrite(&Request{Method: "Put", Filepath: "/foo", Flags: sshFxfWrite | sshFxfCreat}) | |
| require.NoError(t, err) | |
| err = fs.Filecmd(&Request{ | |
| fs := InMemHandler() | |
| _, err := fs.FilePut.Filewrite(&Request{Method: "Put", Filepath: "/foo", Flags: sshFxfWrite | sshFxfCreat}) | |
| require.NoError(t, err) | |
| err = fs.FileCmd.Filecmd(&Request{ |
| return ErrSSHFxBadMessage | ||
| } | ||
|
|
||
| return file.Truncate(int64(attrs.Size)) |
Collaborator
There was a problem hiding this comment.
I’m going to recommend we provide a better example here, because if one were supporting more than one setstat operation, it would need to be repeated. Instead, let’s test the attributes up front:
attrs := r.Attributes()
if attrs == nil {
// Something went wrong parsing attributes
return ErrSSHFxBadMessage
}
if r.AttrFlags().Size {
return file.Truncate(int64(attrs.Size))
}
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #661.
Request.Attributes()returns nil when the attribute blob does not hold every field its flags promise. That is deliberate — #325 / #328 replaced a panic inside the parser with a nil return — butrequest-example.godereferences it:A
SSH_FXP_SETSTATthat setsSSH_FILEXFER_ATTR_SIZEand carries fewer than eight bytes of attributes reaches that line with nil. The panic happens in apacketWorkergoroutine, so the caller cannot recover it and the process ends. I found it by fuzzing a server whoseFilecmdstarted from this example.What this changes
request-example.go: answerErrSSHFxBadMessagewhenAttributes()is nil, instead of dereferencing it.request-attrs.go: say in the doc comment thatAttributes()returns nil for malformed attributes, so callers know they have to check. The comment gave no hint, and the example taught the unchecked pattern.request-example_test.go(new): a regression test that drives the example handler with a short attribute blob. It panics without the fix and passes with it. It calls the handler directly rather than throughclientRequestServerPair, so it also runs on Windows and Plan 9.The library's own parsing is unchanged; only the example and a doc comment.
Verification
Reverting only the
request-example.gohunk makes that test panic atrequest-example.go:160, which is the reported crash.go test ./...is otherwise unchanged by this PR. Note thatTestCleanPathalready fails on master on windows/amd64, before and after this change, so it looks unrelated and platform-specific.🤖 Generated with Claude Code