3

This question is about understanding the reason(s) behind a perceived inconsistency between documented and actual behavior when calling an executable through sudo. When the secure_path option is enabled (default on my system), the search path behave as expected. But when the option is disabled, something strange happens: an executable in /usr/local/bin can be reached without a fully qualified path name despite its location not being in the search path.

System Information

The following software is currently installed on my system:

## Yeah... still haven't migrated to Alma
[me@localhost ~]$ cat /etc/centos-release
CentOS Linux release 8.5.2111

[me@localhost ~]$ bash --version | head -1
GNU bash, version 4.4.20(1)-release (x86_64-redhat-linux-gnu)

[me@localhost ~]$ sudo --version
Sudo version 1.8.29
Sudoers policy plugin version 1.8.29
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.29

[me@localhost ~]$ ssh -V
OpenSSH_8.0p1, OpenSSL 1.1.1k  FIPS 25 Mar 2021

PAM does not set or update the value of the PATH variable on my system:

[me@localhost ~]$ grep --recursive 'pam_env\.so' /etc/pam.d
/etc/pam.d/fingerprint-auth:auth        required      pam_env.so
/etc/pam.d/smartcard-auth:auth        required      pam_env.so
/etc/pam.d/su:auth        required    pam_env.so
/etc/pam.d/password-auth:auth        required      pam_env.so
/etc/pam.d/system-auth:auth        required      pam_env.so

[me@localhost ~]$ sudo cat /etc/security/pam_env.conf /etc/environment | grep PATH
# be useful to be set: NNTPSERVER, LESS, PATH, PAGER, MANPAGER .....
#PATH       DEFAULT=${HOME}/bin:/usr/local/bin:/bin\

My /etc/sudoers file sets a secure_path value for all sudoers:

[me@localhost ~]$ sudo grep --recursive secure_path /etc/sudoers /etc/sudoers.d
/etc/sudoers:Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin

Bash defaults to the following PATH value:

[me@localhost ~]$ env --ignore-environment bash -c 'echo $PATH'
/usr/local/bin:/usr/bin

Finally, I am connected to the system through SSH, whose /etc/ssh/sshd_config file contains this line:

[me@localhost ~]$ sudo grep PATH /etc/sshd_config
# This sshd was compiled with PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin

Replication Procedure

To replicate, I first create a dummy script and install it in /usr/local/bin:

[me@localhost ~]$ cat > dummy <<EOF
#!/usr/bin/bash
echo 'Found!'
EOF

[me@localhost ~]$ sudo install --owner=root --group=root --mode=755 dummy /usr/local/bin

I verify that the search path works as expected when not using sudo:

## The /usr/local/bin location is part of my search path
[me@localhost ~]$ echo $PATH
/home/me/.local/bin:/home/me/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin

## This is expected
[me@localhost ~]$ dummy
Found!

And using sudo, no surprise here either:

## Sudo's secure_path value
[me@localhost ~]$ sudo --user=other env | grep PATH
PATH=/usr/bin:/bin:/usr/sbin:/sbin

## This is expected
[me@localhost ~]$ sudo --user=other which dummy
which: no dummy in (/sbin:/bin:/usr/sbin:/usr/bin)

## This too, of course
[me@localhost ~]$ sudo --user=other dummy
sudo: dummy: command not found

## Indeed, a fully qualified path name is required
[me@localhost ~]$ sudo --user=other /usr/local/bin/dummy
Found!

Then, I disable secure_path (careful here! use of visudo is advised), either by commenting the line out in /etc/sudoers or by creating a file /etc/sudoers.d/local with the following lines:

# Disable secure_path if set
Defaults !secure_path

This should prevent sudo, when called with the --preserve-env switch, from overriding the PATH environment variable with the value of secure_path. And it works as expected.

However, when not using the --preserve-env switch, and not prompting a full login sequence with the --login switch (thereby not sourcing any of Bash's startup files), and with no assignment to PATH in any of PAM environment files, something strange happens:

## Not sure where this PATH value is from, neither from sudo's secure_path option
## (not set), PAM environment files (contain no assignment to PATH), Bash startup
## scripts (not sourced), nor Bash or sshd default PATH values (no match).
[me@localhost ~]$ sudo --user=other env | grep PATH
PATH=/usr/bin:/bin:/usr/sbin:/sbin

## Regardless, this is expected
[me@localhost ~]$ sudo --user=other which dummy
which: no dummy in (/usr/bin:/bin:/usr/sbin:/sbin)

## But wait! What?!?
[me@localhost ~]$ sudo --user=other dummy
Found!

So, how is it that which dummy complains of dummy not in search path while a straight call to dummy without path prefix finds it?

Relevant Documentation

Following are references to various bits of information that I found relevant while researching this question.

Sudo documentation says this about the secure_path option:

Path used for every command run from sudo. If you don't trust the people running sudo to have a sane PATH environment variable you may want to use this. Another use is if you want to have the “root path” be separate from the “user path”. Users in the group specified by the exempt_group option are not affected by secure_path. This option is not set by default.

As per pam_env documentation in man pages, only the /etc/environment, the /etc/security/pam_env.conf and ~/.pam_environment should be processed by the pam_env module by default, unless non-default file names are specified. This is not the case on my system and none of these files set or update the value of PATH.

Bash's man page says:

PATH The search path for commands. It is a colon-separated list of directories in which the shell looks for commands (see COMMAND EXECUTION below). A zero-length (null) directory name in the value of PATH indicates the current directory. A null directory name may appear as two adjacent colons, or as an initial or trailing colon. The default path is system-dependent, and is set by the administrator who installs bash. A common value is “/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin”.

This page of Bash documentation on gnu.org (https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html) explains when the various startup files are sourced. In my demonstration above, none of these files should be sourced since I'm neither spawning new shells in --login or --interactive, nor calling sudo with the --login switch.

This ServerFault answer (https://serverfault.com/questions/833762/where-does-the-bash-path-on-centos-7-get-usr-local-bin-from#answer-838552) explains Bash's default values for the PATH variable. Even though it was answered for Bash on CentOS 7, the answer is still relevant to the Bash version packaged with CentOS 8. As per the accepted answer, the bash source config-top.h has this:

/* The default value of the PATH variable. */
#ifndef DEFAULT_PATH_VALUE
#define DEFAULT_PATH_VALUE \
  "/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:."
#endif

/* The value for PATH when invoking `command -p'.  This is only used when
   the Posix.2 confstr () function, or CS_PATH define are not present. */
#ifndef STANDARD_UTILS_PATH
#define STANDARD_UTILS_PATH \
  "/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc"
#endif
2
  • Some new information which I had not realized could be relevant: I'm connected to the system through SSH, whose configuration file says that "This sshd was compiled with PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin". I'm not quite sure of what this implies, but there could be a connection, as it contains the /usr/local/bin location. Updating the question with this new information.
    – mesr
    Commented Jun 21, 2022 at 21:27
  • Yet another clue could be given by Bash's default (hard-coded) PATH value which, on the system under consideration, also contains the /usr/local/bin entry. Updating the question.
    – mesr
    Commented Jun 21, 2022 at 22:00

1 Answer 1

1

I believe you're seeing the interplay between env_reset and secure_path.

When enabled:

  • secure_path resets PATH to a known-good value
  • env_reset resets most environment variables, including PATH (exact behaviour will depend on other options and configuration, including secure_path)

The question is: what does each reset affect?

The second, env_reset affects the programs started by sudo. On the other hand, secure_path also affects sudo itself. Without it, sudo uses the (calling) user's PATH to look up programs. But:

  • When starting the program,
    • if env_reset is enabled (the default), and
      • PATH is not exempt from being reset (e.g., via env_keep), then,
        • the program will be started with ...
          • a reset value of PATH
          • (as well as other environment variables)

So when you call which or env or something else, it won't see the PATH that sudo itself was using.

1
  • 1
    I believe that you are quite right. This comes down to the fact that sudo looks for the target command in the caller's environment, not in the target's. My mistake, I now realize, was to assume that sudo always ran its target command in a shell, although sometimes implicitly (kind of when called with the --login switch, but without the login procedure). Further insights on this aspect of sudo's behavior can be found in the accepted answer to this other question: stackoverflow.com/questions/37817693/what-shell-does-sudo-use.
    – mesr
    Commented Jul 18, 2022 at 13:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .