Why are the arguments supplied for the command run through ssh interpreted by shell before they are passed to the command on the server side?

Darren Tucker dtucker at dtucker.net
Sat Jan 11 23:46:33 AEDT 2020


On Sat, 11 Jan 2020 at 20:59, Yuri <yuri at rawbw.com> wrote:
[...]
> It's not obvious why does it have to be this way. ssh sends the command
> as an array of strings.
>
> The first string is the command, and the
> subsequent strings are arguments. It can easily call the same command
> with the same arguments on the remote host.

Why do you say that?  From RFC 4254 section 6.5:

"""
      byte      SSH_MSG_CHANNEL_REQUEST
      uint32    recipient channel
      string    "exec"
      boolean   want reply
      string    command

   This message will request that the server start the execution of the
   given command.  The 'command' string may contain a path.  Normal
   precautions MUST be taken to prevent the execution of unauthorized
   commands.
"""

Note the single string specifying the command.

> Also this sentence from the man page seems to be false:
>
>  > If a command is specified, it is executed on the remote host instead
> of a login shell.
>
> Login shell still interprets the command.

No, it's interpreted by a non-login shell.  A login shell is a subset
of shell invocations with some specific behaviour.  The bash man page
describes some of this:

"""
INVOCATION
       A login shell is one whose first character of argument zero is a -, or
       one started with the --login option.
[...]
       Login shells:
         On login (subject to the -noprofile option):
               if /etc/profile exists, source it.

               if ~/.bash_profile exists, source it,
                 else if ~/.bash_login exists, source it,
                   else if ~/.profile exists, source it.

         On exit:
               if ~/.bash_logout exists, source it.
"""

> Interestingly, the shell
> process isn't running on the remote host, the command is a direct child
> of sshd.

That's probably because the shell is skipping the fork in the simple
command case as an optimization.  If you repeat the experiment with a
non-trivial command you'll see something like this:

$ ssh localhost "sleep 1000 | sleep 1000"
[...]
$ ps -eaf | grep "sleep 1000"
dtucker  22321     1  0 22:56 ?        00:00:00 bash -c sleep 1000 | sleep 1000
[...]
$ pstree -s -p 22355
systemd(1)---bash(22321)---sleep(22355)

-- 
Darren Tucker (dtucker at dtucker.net)
GPG key 11EAA6FA / A86E 3E07 5B19 5880 E860  37F4 9357 ECEF 11EA A6FA (new)
    Good judgement comes with experience. Unfortunately, the experience
usually comes from bad judgement.


More information about the openssh-unix-dev mailing list