quirk in bash security check (privileged mode)

Did you know the name given to bash affects its behavior?

burrows@box:/tmp/priv$ ln -s /bin/bash sh
burrows@box:/tmp/priv$ ln -s /bin/bash ba
burrows@box:/tmp/priv$ ./ba -c "set -o | grep posix"
posix           off
burrows@box:/tmp/priv$ ./sh -c "set -o | grep posix"
posix           on

This is a little odd, but it gets stranger.

Here is a snippet from the bash manpage discussing the -p option.

Turn on privileged mode. In this mode, the $ENV and $BASH_ENV files are not processed, shell functions are not inherited from the environment, and the SHELLOPTS, BASHOPTS, CDPATH, and GLOBIGNORE variables, if they appear in the environment, are ignored. If the shell is started with the effective user (group) id not equal to the real user (group) id, and the -p option is not supplied, these actions are taken and the effective user id is set to the real user id. If the -p option is supplied at startup, the effective user id is not reset. Turning this option off causes the effective user and group ids to be set to the real user and group ids.

In particular, if we don’t specify the -p option we should expect bash to drop setuid privileges.

alice@box:/tmp/priv$ cp /bin/bash bash
alice@box:/tmp/priv$ chmod u+s bash
alice@box:/tmp/priv$ id
uid=1004(alice) gid=1005(gamers) groups=1004(alice),1005(gamers)

bob@box:/tmp/priv$ ./bash
bash-3.1$ id
uid=1002(bob) gid=1005(gamers) groups=1002(bob),1005(gamers)

bob@box:/tmp/priv$ ./bash -p
bash-3.1$ id
uid=1002(bob) gid=1005(gamers) euid=1004(alice) groups=1002(bob),1005(gamers)

The code in upstream bash responsible for dropping privileges is in shell.c and it looks like this.

int
main()
{
    // ...

    running_setuid = uidget ();

    // ...

    // privileged_mode is set by the -p flag
    if (running_setuid && privileged_mode == 0)
        disable_priv_mode ();

    // ...
}

/* Fetch the current set of uids and gids and return 1 if we're
   running setuid or setgid. */
static int
uidget ()
{
  uid_t u;

  u = getuid ();
  if (current_user.uid != u)
    {
      FREE (current_user.user_name);
      FREE (current_user.shell);
      FREE (current_user.home_dir);
      current_user.user_name = current_user.shell =
          current_user.home_dir = (char *)NULL;
    }
  current_user.uid = u;
  current_user.gid = getgid ();
  current_user.euid = geteuid ();
  current_user.egid = getegid ();

  /* See whether or not we are running setuid or setgid. */
  return (current_user.uid != current_user.euid) ||
       (current_user.gid != current_user.egid);
}

void
disable_priv_mode ()
{
  setuid (current_user.uid);
  setgid (current_user.gid);
  current_user.euid = current_user.uid;
  current_user.egid = current_user.gid;
}

However, the debian bash fork includes this patch.

-  if (running_setuid && privileged_mode == 0)
+  if (running_setuid && privileged_mode == 0 && act_like_sh == 0)
     disable_priv_mode ();

This new condition, act_like_sh; how does bash determine it’s status? Well by the name of the bash process of course.

int
main()
{
    // ...

    running_setuid = uidget ();

    // ...

    set_shell_name (argv[0]);

    // ...    

    // privileged_mode is set by the -p flag
    if (running_setuid && privileged_mode == 0 && act_like_sh)
        disable_priv_mode ();

    // ...
}

static void
set_shell_name (argv0)
     char *argv0;
{
  /* Here's a hack.  If the name of this shell is "sh", then don't
     do any startup files; just try to be more like /bin/sh. */
  shell_name = argv0 ? base_pathname (argv0) : PROGRAM;

  if (*shell_name == '-')
    {
      shell_name++;
      login_shell++;
    }

  if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0')
    act_like_sh++;

  // ...
}

bash-debian will never drop privileges if the process is named sh.

alice@debian:/tmp/priv$ cp /bin/bash sh
alice@debian:/tmp/priv$ chmod u+s sh

bob@debian:/tmp/priv$ ./sh
sh-3.1$ id
uid=1002(bob) gid=1005(gamers) euid=1004(alice) groups=1002(bob),1005(gamers)

bob@debian:/tmp/priv$ ./sh -p
sh-3.1$ id
uid=1002(bob) gid=1005(gamers) euid=1004(alice) groups=1002(bob),1005(gamers)

In summary, bash-upstream will always drop privileges if -p is not specified; bash-debian will never drop privileges if the process has name sh.

Debian based systems should probably update their bash manpage to reflect this abnormality; for example.

Tangentially, here is a good explanation of setuid + scripts.

 
36
Kudos
 
36
Kudos

Now read this

manual deployment of extensions in chromium

Chrom(ium) let’s us install an extension (crx file) by putting it into a special directory. The details are discussed on this page. In particular the page says to use these directories on linux. /opt/google/chrome/extensions/... Continue →