46

On my fedora VM, when running with my user account I have /usr/local/bin in my path:

[justin@justin-fedora12 ~]$ env | grep PATH
 PATH=/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/justin/bin

And likewise when running su:

[justin@justin-fedora12 ~]$ su -
Password: 
[root@justin-fedora12 justin]# env | grep PATH
PATH=/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/justin/bin

However, when running via sudo, this directory is not in the path:

[root@justin-fedora12 justin]# exit
[justin@justin-fedora12 ~]$ sudo bash
[root@justin-fedora12 ~]# env | grep PATH
PATH=/usr/kerberos/sbin:/usr/kerberos/bin:/sbin:/bin:/usr/sbin:/usr/bin

Why would the path be different when running via sudo?

41

Take a look at /etc/sudoers. The default file in Fedora (as well as in RHEL, and also Ubuntu and similar) includes this line:

Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin

Which ensures that your path is clean when running binaries under sudo. This helps protect against some of the concerns noted in this question. It's also convenient if you don't have /sbin and /usr/sbin in your own path.

| improve this answer | |
  • Ah, I see that in my file. So, not that I want to, but if I added /usr/local/bin to this directive then I would see it in my path when running via sudo, right? – Justin Ethier Mar 5 '11 at 16:25
  • I just tried it and now I see /usr/local/bin. Thank you so much for explaining this! – Justin Ethier Mar 5 '11 at 16:27
  • What about adding your users's path for scripts and binaries, so you don't have to write the absolute path when you must sudo for example a script in your ~/bin (or whatever path you use)? I just made the change - it works, only thought there might be a flip side to it? – Emanuel Berg Oct 15 '12 at 2:01
  • @mattdm Yes, Ubuntu as well, as I came across that issue in Ubuntu Vivid when playing with VM. The same for Debian. – kenorb Dec 24 '15 at 17:22
  • Very good to know; thanks! As others have mentioned you can add env "PATH=$PATH" to the command to temporarily bring in the current user's path for one command. For more permanent use of a command with sudo, rather than editing /etc/sudoers it might be more surgical to simply do a sudo ln -s /usr/local/bin/cmd cmd inside /usr/sbin to link the command inside a directory already on the sudoers path. Then you can always use the command with sudo without pulling in all the other commands in /usr/local/bin. – Garret Wilson May 16 at 15:53
11

The command su - will execute the root users profile and take on that user's environment including path etc. sudo does not do that.

If you'd like sudo to behave like su - then use the option sudo -i [command which will execute the user's profile

If you'd like su - to behave like sudo then don't use the hyphen - just use su [command]

| improve this answer | |
4

You can check why (it's different) by running sudo sudo -V.

For example on Linux run:

$ sudo sudo -V | grep PATH
Value to override user's $PATH with: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Note: On macOS/BSD, just run: sudo sudo -V.

The above list is restricted due to default security policy plugin in some Linux distributions.


This is further explained in man sudoers:

If the secure_path option is set, its value will be used for the PATH environment variable.

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 that's the case, you can change that by running sudo visudo and editing the configuration file and modifying your secure_path (adding extra path separated by :) or add your user into exempt_group (so you won't be affected by secure_path options).

Or in order to pass user's PATH temporary, you can run:

sudo env PATH="$PATH" my_command

and you can check that by:

sudo env PATH="$PATH" env | grep ^PATH

See also: How to make sudo preserve $PATH?


Other reason why the environment could be different for sudo, is because you could have env_reset option enabled in your sudoers file. This causes commands to be executed with a new, minimal environment.

So you can use env_keep option (not recommended for security reasons) to preserve your user's environment variables:

Defaults        env_reset
Defaults        env_keep += "PATH PYTHONPATH"
| improve this answer | |
1

In most linuxes, you install programs via the package management, and get updates in a regular way. If you install something circumventing the package management it will be installed in /usr/local/bin (for example, or .../sbin, or /opt) and not get regular updates.

I guess therefore the programs aren't considered to be that secure, and not put into roots PATH by default.

| improve this answer | |
  • +1 - Cool, I was wondering why it was not in the path, and that makes sense. For what it's worth, I was building node.js from scratch to play around with it, so it makes sense why it would have been put there, and why sudo would exclude this directory by default. – Justin Ethier Mar 5 '11 at 16:29
  • @Justin Ethier: off topic, but see bugzilla.redhat.com/show_bug.cgi?id=634911 – mattdm Mar 6 '11 at 18:53
1

I've just tried this out for myself and I didn't see the behaviour you were seeing - my path remained the same, so maybe your sudo configuration is different. If you check man sudoers you'll see there is an option called secure_path which resets PATH - it sounds like this option might have been enabled.

| improve this answer | |
  • Interesting. This was on Fedora 12, for what it's worth... – Justin Ethier Mar 5 '11 at 16:22
1

Because when you use sudo bash, bash doesn't not act as a login shell. Try again with sudo bash -l and you should see the same result as su -.

If that is correct, then the difference in PATH lies in the configuration files: /etc/profile, ~/.bash_profile, ~/.bash_login, ~/.profile are executed (in that order) for a login shell, while ~/.bashrc is executed for a non-login interactive shell.

| improve this answer | |
1

Old question, I know, but I stumbled in here just now because I was investigating this exact problem.

For some reason /usr/local/bin was only in the PATH when becoming root via sudo su -. When using sudo -i it wasn't there. Of course I now know I can add it to /etc/sudoers, but that still didn't explain why it is already there after su -. Where did this part of PATH come from?

After a lot of grepping and searching I found the answer:

The default path containing '/usr/local/bin' is actually hardcoded in su(1).

So no pam configuration, profile, bashrc or anything was responsible for selectively adding this element. It was always already there when su took over. And since sudo does not invoke su at all but uses it's own configuration, it was missing after sudo -i

I found this to be true on RHEL6 and RHEL7. I didn't check any other version or distribution.

| improve this answer | |
  • Don't ask me how I verified this.. Okay, if you insist: I hex-edited a copy of the su binary, changed /usr/local/bin into something else and invoked the copy. My PATH now contained the modified string... Good kids and non-lazy sysadmins of course just download the source and check in there. ;-) – Oscar May 22 '19 at 15:43
  • Thanks, I was wondering how it was working. – emmdee Mar 10 at 20:20

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.