Skip to content

honor permissions in SSH_FXP_MKDIR attrs - #700

Open
likitha011 wants to merge 4 commits into
pkg:masterfrom
likitha011:mkdir-honor-permissions
Open

likitha011 wants to merge 4 commits into
pkg:masterfrom
likitha011:mkdir-honor-permissions

Conversation

@likitha011

Copy link
Copy Markdown
Contributor

Repro: send SSH_FXP_MKDIR with SSH_FILEXFER_ATTR_PERMISSIONS and mode 0700 (sshfs does this for mkdir -m 700). The Server creates the directory as 0755, so other local users can list and read it.
Cause: sshFxpMkdirPacket.UnmarshalBinary reads the attrs flags but drops the attrs body, and handlePacket calls os.Mkdir(path, 0o755) unconditionally. requestFromPacket also never copies the flags/attrs for Mkdir, so RequestServer handlers cannot honor the mode either.
Fix: keep the attrs on the packet and apply the permission bits the same way OPEN already does (FileMode() & os.ModePerm). Without the permissions flag the Server still uses 0755. Covered by TestMkdirWithPermissions and TestRequestFromMkdirPacketAttrs, which fail with the old server.go/request.go.

The Server ignored the ATTRS sent with SSH_FXP_MKDIR and always created
the directory with mode 0755, so a client asking for a private directory
(for example sshfs forwarding `mkdir -m 700`) got one that any local user
could read. RequestServer handlers never saw the attrs either, since
requestFromPacket did not copy them into the Request.

Keep the attrs on sshFxpMkdirPacket, apply the requested permission bits
in the Server the same way OPEN does, and pass the flags and attrs on to
RequestServer handlers. Without SSH_FILEXFER_ATTR_PERMISSIONS the Server
still uses 0755.
Comment thread packet.go Outdated
Comment on lines +1047 to +1049
if fs, ok := p.Attrs.(*FileStat); ok {
b = marshalFileStat(b, p.Flags, fs)
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please copy the implementation in sshFxpOpenPacket https://github.com/pkg/sftp/blob/master/packet.go#L816-L824

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, sshFxpMkdirPacket now has a marshalPacket that mirrors the open one ([]byte, os.FileInfo, *FileStat, else marshal), with MarshalBinary just appending header and payload.

Comment thread server.go Outdated
Comment on lines +264 to +274
mode := os.FileMode(0o755)
var err error
if p.Flags&sshFileXferAttrPermissions != 0 {
var fs *FileStat
if fs, err = p.unmarshalFileStat(p.Flags); err == nil {
mode = fs.FileMode() & os.ModePerm
}
}
if err == nil {
err = os.Mkdir(s.toLocalPath(p.Path), mode)
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be converted to a respond receiver method to match sshFxpOpenPacket

This will allow for an early return design, rather than needing to juggle declarations and scopes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, sshFxpMkdirPacket has a respond method now, laid out like the open one with early returns, and the inline case in handlePacket is gone so it dispatches through serverRespondablePacket. Tests, integration and race runs still pass.

Comment thread server.go Outdated
}

func (p *sshFxpMkdirPacket) respond(svr *Server) responsePacket {
mode := os.FileMode(0o755)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, https://github.com/openssh/openssh-portable/blob/master/sftp-server.c#L1206-L1207

	mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
	    a.perm & 07777 : 0777;

Turns out we want to be using 0o777 for directories, and 0o666 for files.

(It being up to the umask to remove undesired permission bits.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Mkdir now defaults to 0o777 and open to 0o666, leaving the rest to umask.

@puellanivis puellanivis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P.S.

Comment thread packet.go Outdated
Comment on lines +1029 to +1031
Flags uint32
Path string
Attrs any

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, also while we’re here, we can reorder these to be in packet encoded order?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, it is ID, Path, Flags, Attrs now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants