[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Weird set -u error



On Sat, Aug 27, 2022 at 05:12:57PM +1000, David wrote:
> I have modified my ssh environment so that it is not the default.
> But I do see a similar error message, using ssh from stable Debian 11.
> 
> [david@kablamm ~]$ ( bash -cu : )
> [david@kablamm ~]$ ssh kablamm
> Linux kablamm 5.10.0-16-amd64 #1 SMP Debian 5.10.127-2 (2022-07-23) x86_64
> Last login: Sat Aug 27 17:00:13 2022 from 10.1.1.2
> [david@kablamm ~]$ ( bash -cu : )
> /etc/bash.bashrc: line 7: PS1: unbound variable
> [david@kablamm ~]$

Same here, with no special trickery.


unicorn:~$ (bash -cu :)
unicorn:~$ ssh localhost
greg@localhost's password: 
Linux unicorn 5.10.0-17-amd64 #1 SMP Debian 5.10.136-1 (2022-08-13) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Aug 16 07:35:44 2022
unicorn:~$ (bash -cu :)
/etc/bash.bashrc: line 7: PS1: unbound variable


So it's definitely coming from the Debian bash patch that triggeres the
special behavior when bash detects itself to be a child of ssh.  I've
got no clue (yet!) why it's only triggered using a subshell.

I also can't explain this (still inside the ssh localhost session):


unicorn:~$ (bash -c 'declare -p PS1')
declare -- PS1="\\h:\\w\\\$ "
unicorn:~$ (bash -cu 'declare -p PS1')
/etc/bash.bashrc: line 7: PS1: unbound variable
/etc/bash.bashrc: line 1: declare: PS1: not found


Why would adding the -u option change whether PS1 gets unset?  Not a clue.

Anyway, this is the segment of the upstream bash source (config-top.h)
where the compile-time ssh detection feature can be enabled:


/* Define this if you want bash to try to check whether it's being run by
   sshd and source the .bashrc if so (like the rshd behavior).  This checks
   for the presence of SSH_CLIENT or SSH2_CLIENT in the initial environment,
   which can be fooled under certain not-uncommon circumstances. */
/* #define SSH_SOURCE_BASHRC */


One of the Debian patches removes the comments around that preprocessor
variable.  And here in shell.c is the function where it gets used:


static void
run_startup_files ()
{
#if defined (JOB_CONTROL)
  int old_job_control;
#endif
  int sourced_login, run_by_ssh;

  /* get the rshd/sshd case out of the way first. */
  if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 &&
      act_like_sh == 0 && command_execution_string)
    {
#ifdef SSH_SOURCE_BASHRC
      run_by_ssh = (find_variable ("SSH_CLIENT") != (SHELL_VAR *)0) ||
                   (find_variable ("SSH2_CLIENT") != (SHELL_VAR *)0);
#else
      run_by_ssh = 0;
#endif

      /* If we were run by sshd or we think we were run by rshd, execute
         ~/.bashrc if we are a top-level shell. */
      if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)
        {
#ifdef SYS_BASHRC
#  if defined (__OPENNT)
          maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1);
#  else
          maybe_execute_file (SYS_BASHRC, 1);
#  endif
#endif
          maybe_execute_file (bashrc_file, 1);
          return;
        }
    }
[...]


That SYS_BASHRC thing is /etc/bash.bashrc in Debian (another one of the
Debian patches turns this on -- it's not enabled by default in upstream
bash).

Now, that "shell_level < 2" check is also intriguing.

Starting from a plain old regular urxvt running bash in my local X session
which was launched by startx:


unicorn:~$ declare -p SHLVL
declare -x SHLVL="2"
unicorn:~$ ssh localhost
greg@localhost's password: 
[...]
unicorn:~$ declare -p SHLVL
declare -x SHLVL="1"
unicorn:~$ bash -uc 'declare -p SHLVL'
declare -x SHLVL="2"
unicorn:~$ (bash -uc 'declare -p SHLVL')
/etc/bash.bashrc: line 7: PS1: unbound variable
declare -x SHLVL="1"


It looks like the subshell resets the shell_level, which is why the
behavior in run_startup_files() changes.

I still don't know how -u is involved (why the behavior of (bash -uc)
is different from that of (bash -c)).  I'll leave that analysis to
someone who actually cares about -u.

In any event, it's the confluence of FIVE factors here that matters:

 1) Using a version of bash that was compiled with SSH_SOURCE_BASHRC.
 2) Being in an ssh session, so that SSH_CLIENT is set.
 3) Using () to force a subshell which resets the shell_level.
 4) Using -u which somehow unsets PS1.
 5) Using code that checks the value of $PS1 in a startup file.

Remove any one of those factors, and the problem doesn't manifest.


Reply to: