command [argument ...] in ssh(1): a footgun

raf ssh at raf.org
Wed May 31 14:14:35 AEST 2023


On Tue, May 30, 2023 at 05:02:21PM +0000, Peter Stuge <peter at stuge.se> wrote:

> raf wrote:
> > > > Not knowing the details of each user's login shell is
> > > > precisely the reason that ssh couldn't ever do the
> > > > quoting itself.
> > > 
> > > The footgun is unrelated to shells.
> > > 
> > > The SSH_MSG_CHANNEL_REQUEST protocol message for "exec" (RFC 4254)
> > > channels which are used to run a single remote command contains
> > > exactly one string for the command.
> > > 
> > > sshd (see bottom of do_child() in session.c) runs that command string as:
> > > 
> > > remote_users_shell -c command
> > 
> > I'm aware of that. That's why I said what I said.
> > Sorry, but I don't understand what point you are making.
> 
> My point wasn't directed at you specifically, rather at the thread in general.
> 
> 
> Jochen Bern wrote:
> > Let's summarize the general situation, though:
> > -- We cannot reduce the local shell's influence re: quoting to zero
> 
> This happens before the ssh client process starts.
> 
> 
> > -- We cannot reduce the remote shell's influence to zero as long as
> >     sshd(8) uses that to execute the command.
> 
> As I pointed out sshd always uses the shell. (Bottom of session.c:do_child())
> 
> 
> > -- If we avoid that and execv() the command directly,
> 
> The protocol transfers a single command string to the server. The
> server has no array to pass to execv().

Nor should it. That would infantalize ssh. It would
mean that shell globbing and pipelines and for loops
would stop working, along with all the rest of its
syntax (whatever that might be), without requiring the
user to type in sh -c "'...'" themselves. I think the
existing method is great. It supports everything that
the remote shell is capable of, whatever that remote
shell might happen to be.

The only problem (it seems) is that not everyone
realises that they might sometimes need to include
quoting of some kind in the local ssh command that
needs to make it to the remote command where it is
executed. Although that should quickly become apparent
to anyone who needs to know it (like the first time you
realise that the globbing needs to happen at the remote
end). This can be fixed with a documentation change to
better prepare user expectations, not with a code
change to make ssh less capable. I'm not saying that a
documentation change is necessary, only that it would
be sufficient.

If examples are too verbose, perhaps the manual could
just add a mention of the fact that the resulting
command (where it mentions that local arguments are
joined with a space) is executed remotely by passing it
to the remote user's login shell as its -c option
argument. That could be a short addition that might do
the trick for preparing user expectations. Personally,
I don't think even that is needed, but my opinion isn't
important. And it wouldn't hurt.

Actually, I'm trying to find the mention in the manpage
that started this and can't find it. It doesn't mention
[arguments...] after [command] like I think the OP
asked to have removed. I must be misremembering. The
synopsis ends with: "[command]". And the DESCRIPTION
section (paragraph 3) says:

  If a command is specified, it is executed on the
  remote host instead of a login shell.

I can't see where it says that arguments are joined
with a space. Maybe I'm reading it wrong.

Later (AUTHENTICATION section) it says:

  When the user's identity has been accepted by the
  server, the server either executes the given
  command in a non-interactive session or, if no
  command has been specified, logs into the machine
  and gives the user a normal shell as an interactive
  session.  All communication with the remote command
  or shell will be automatically encrypted.

Perhaps this could be added after that paragraph:

  If a command has been specified, it is executed by
  passing it to the remote user's login shell as the
  argument to its -c option (e.g., sh -c '...'). If
  multiple command line arguments are specified, they
  are first concatenated, with a space between each, to
  form a single argument for the -c option. Note that
  there are cases where extra quoting is needed for the
  command to be interpreted as intended by the remote
  shell.

That tells the user which shell is used, and it tells
how it is executed, so the user knows to read about the
-c option in their own shell's documentation if
necessary, and it points out the fact that the user
needs to realise that the command is being specified
and interpreted in a local shell, to be interpreted
again by a remote shell, so they need to take the
combination of local and remote shell syntax into
consideration.

> > I *could* see a "switch to remote direct execv()" *option* on the (far) 
> > horizon, but not a change of the default behavior.
> 
> I tried to make clear that the protocol does not allow such an option.
> 
> 
> > use some sort of encoding on the command transmitted from ssh to sshd
> 
> The protocol message is binary transparent; it's certainly possible
> to serialize a data structure into the command string and use a shell
> on the server that deserializes its -c argument. Seems convoluted though.

None of that sounds (to me) like it would serve a
useful purpose anyway.

> //Peter

cheers,
raf



More information about the openssh-unix-dev mailing list