7

There are two Python interpreters installed:

[user@localhost ~]$ /usr/bin/python -V && /usr/local/bin/python -V
Python 2.4.3
Python 2.7.6

Sudo changes PATH when executed:

[user@localhost ~]$ env | grep PATH && sudo env | grep PATH
PATH=/usr/kerberos/bin:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/user/bin
PATH=/usr/bin:/bin

Yet Python run through sudo is the same as the one run directly:

[user@localhost ~]$ sudo python -V && python -V
Python 2.7.6
Python 2.7.6

I would expect sudo python to run /usr/bin/python which is the only one visible on the modified PATH. Why does it run /usr/local/bin/python instead?

I asked this question on sudo-users mailing list but we couldn't find the reason for this behavior in discussion with sudo maintainer Todd C. Miller.

For reference:

[user@localhost ~]$ sudo -l
Matching Defaults entries for user on this host:
    requiretty, !visiblepw, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR LS_COLORS MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS
    LC_CTYPE LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE LC_TIME LC_ALL LANGUAGE
    LINGUAS _XKB_CHARSET XAUTHORITY"

Runas and Command-specific defaults for user:


User user may run the following commands on this host:
    (ALL) NOPASSWD: ALL


[user@localhost ~]$ sudo sudo -V
Sudo version 1.7.2p1

Sudoers path: /etc/sudoers
nsswitch path: /etc/nsswitch.conf
ldap.conf path: /etc/ldap.conf
ldap.secret path: /etc/ldap.secret
Authentication methods: 'pam'
Syslog facility if syslog is being used for logging: authpriv
Syslog priority to use when user authenticates successfully: notice
Syslog priority to use when user authenticates unsuccessfully: alert
Ignore '.' in $PATH
Send mail if the user is not in sudoers
Use a separate timestamp for each user/tty combo
Lecture user the first time they run sudo
Require users to authenticate by default
Root may run sudo
Allow some information gathering to give useful error messages
Visudo will honor the EDITOR environment variable
Set the LOGNAME and USER environment variables
Length at which to wrap log file lines (0 for no wrap): 80
Authentication timestamp timeout: 5 minutes
Password prompt timeout: 5 minutes
Number of tries to enter a password: 3
Umask to use or 0777 to use user's: 022
Path to mail program: /usr/sbin/sendmail
Flags for mail program: -t
Address to send mail to: root
Subject line for mail messages: *** SECURITY information for %h ***
Incorrect password message: Sorry, try again.
Path to authentication timestamp dir: /var/run/sudo
Default password prompt: [sudo] password for %p: 
Default user to run commands as: root
Path to the editor for use by visudo: /bin/vi
When to require a password for 'list' pseudocommand: any
When to require a password for 'verify' pseudocommand: all
File containing dummy exec functions: /usr/libexec/sudo_noexec.so
File descriptors >= 3 will be closed before executing a command
Reset the environment to a default set of variables
Environment variables to check for sanity:
        TERM
        LINGUAS
        LC_*
        LANGUAGE
        LANG
        COLORTERM
Environment variables to remove:
        RUBYOPT
        RUBYLIB
        PYTHONINSPECT
        PYTHONPATH
        PYTHONHOME
        TMPPREFIX
        ZDOTDIR
        READNULLCMD
        NULLCMD
        FPATH
        PERL5DB
        PERL5OPT
        PERL5LIB
        PERLLIB
        PERLIO_DEBUG 
        JAVA_TOOL_OPTIONS
        SHELLOPTS
        GLOBIGNORE
        PS4
        BASH_ENV
        ENV
        TERMCAP
        TERMPATH
        TERMINFO_DIRS
        TERMINFO
        _RLD*
        LD_*
        PATH_LOCALE
        NLSPATH
        HOSTALIASES
        RES_OPTIONS
        LOCALDOMAIN
        CDPATH
        IFS
Environment variables to preserve:
        XAUTHORIZATION
        XAUTHORITY
        TZ
        PS2
        PS1
        PATH
        MAIL
        LS_COLORS
        KRB5CCNAME
        HOSTNAME
        HOME
        DISPLAY
        COLORS
Locale to use while parsing sudoers: C
Local IP address and netmask pairs:
        10.0.2.15 / 255.255.255.0
        fe80::a00:27ff:febb:56ce / ffff:ffff:ffff:ffff::


[user@localhost ~]$ sudo cat /etc/sudoers | grep -v -E '^#|^$'
Defaults    requiretty
Defaults   !visiblepw
Defaults    env_reset
Defaults    env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR \
                        LS_COLORS MAIL PS1 PS2 QTDIR USERNAME \
                        LANG LC_ADDRESS LC_CTYPE LC_COLLATE LC_IDENTIFICATION \
                        LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC \
                        LC_PAPER LC_TELEPHONE LC_TIME LC_ALL LANGUAGE LINGUAS \
                        _XKB_CHARSET XAUTHORITY"
root    ALL=(ALL)       ALL
user    ALL=(ALL)       NOPASSWD: ALL


[user@localhost ~]$ which sudo && command -V sudo
/usr/bin/sudo
sudo is hashed (/usr/bin/sudo)

[user@localhost ~]$ cat /etc/redhat-release 
Red Hat Enterprise Linux Server release 5.10 (Tikanga)
  • 1
    Environment variables to preserve: ... PATH sounds like an explanation. – peterph Mar 5 '14 at 21:47
  • @peterph Then why does env show different PATH when run with sudo? – Piotr Dobrogost Mar 5 '14 at 21:55
  • Can you post your /etc/sudoers? Also, can you verify you don't have an alias set for sudo such as alias='sudo -i'? You can check that with which sudo. – yoonix Mar 5 '14 at 22:05
  • In your PATH, /usr/local/bin preceeds /usr/bin. I think it is somehow expected to stop the search and run the executable once it is found. And the location it gets to be found is /usr/local/bin the first time. Unless of course your sudo was compiled with a different default PATH – MelBurslan Mar 5 '14 at 22:20
  • 1
    @Mel_Burslan And the location it gets to be found is /usr/local/bin the first time – I'm not sure what you mean here. Running sudo env | grep PATH clearly shows what's the PATH when operating with sudo. The question is why sudo python does not act according to this PATH? – Piotr Dobrogost Mar 5 '14 at 22:27
6

You are getting confused between the PATH which is in the actual sudo execution environment and the PATH which sudo sets in the environment of the program which it runs. From the sudo manual:

When sudo runs a command, it calls fork(2), sets up the execution environment as described above, and calls the execve system call in the child process.

With execve you specify the environment that you want the child process to have, ie it can be different from the parent process.

Often secure_path will be set in /etc/sudoers:

secure_path

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.

If this is set, sudo will both search for the command in this PATH and set this in the environment of the command it runs. It will also show up in the output of sudo sudo -V with a line like:

Value to override user's $PATH with: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

However in your case this is not set, so sudo will use the PATH in its own execution environment (which in this case is inherited from the parent shell). Although it has been configured to ignore the current directory if this has been put in the PATH:

Ignore '.' in $PATH

Since env_reset is in your /etc/sudoers (and PATH is not in the env_keep string), the PATH that sudo sets in the command it calls will be defined by PAM or by /etc/environment and is thus different from the PATH sudo uses to search for its location:

By default, the env_reset option is enabled. This causes commands to be executed with a new, minimal environment. On AIX (and Linux systems without PAM), the environment is initialized with the contents of the /etc/environment file. The new environment contains the TERM, PATH, HOME, MAIL, SHELL, LOGNAME, USER, USERNAME and SUDO_* variables in addition to variables from the invoking process permitted by the env_check and env_keep options.

To run the python in the PATH set by sudo, you should do something like this:

sudo env python -V

This way it is not sudo itself which is searching for the command, rather env will have the environment set by sudo and env will search for the command there.

  • If this is set, sudo will both search for the command in this PATH and set this in the environment of the command it runs. – this is much clearer than brief Path used for every command run from sudo. in the sudoers man page. – Piotr Dobrogost Mar 6 '14 at 8:44
  • @Piotr, yes, the sudoers man page really isn't that clear on this. If you search through it for all the places PATH is mentioned, you start to piece together what is happening though. – Graeme Mar 6 '14 at 10:36
  • I posted a follow-up which you might be interested in – Mismatch between sys.executable and sys.version in Python – Piotr Dobrogost Mar 6 '14 at 21:49
0

Graeme's answer is pretty exhaustive, yet there are two things, that should be said explicitly even though they are not answer to your question:

1 . If safety and security are your concern - which it should be when you use

(ALL) NOPASSWD: ALL

(no matter for what users) - do use secure_path. Otherwise a malicious script marked as executable pretty much anywhere on your system can wreak havoc on (not just) the local machine. And the script doesn't have to be placed on your system directly - a network file system mounted without noexec would do as well.

2 . If safety and security really are your concern, do not use

(ALL) NOPASSWD: ALL

at all. I'm not entirely sure who came up with this utterly stupid (more explicit word redacted) idea of using it as default first, but it simply is far too permissive and dangerous - even a slight typo can ruin (not just) your day. Specify some commands that require root privileges (or use setcap) and allow access to these. Obviously, anything like a shell (and su for those who are used to sudo su) or any other interpreter (Python, Perl, Ruby – you name it) is out of question. By the way, C can be interpreted as well. It may be a bit more intricate to set up if you are using poorly designed programs, though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.