0

Many says for security reasons the current directory is not in the $PATH variable and Linux does not look in the current directory to see whether a specific command is available from that directory. but I did cd /usr/bin then do ls and it worked just fine; also I did echo $PATH and the output contains /usr/bin.

You should notice that for security reasons the current directory is not in the $PATHvariable and Linux does not look in the current directory to see whether a specific command is available from that directory.

Red Hat® RHCSATM/RHCE® 7 Cert Guide by Sander van Vugt

Why am I able to run ls while being in /usr/bin?

2 Answers 2

6

linux does not look in the current directory to see whether a specific command is available from that directory

That's true, but it does look in all directories mentioned in $PATH, even though you might be in such a directory at that moment.

To word it in another way, if . is not in your $PATH, it doesn't matter where you are, it will always search the same directories to see whether a specific command is available there.

5
  • But as I understood the current directory should not be in $PATH why its still in $PATH after I changed to /usr/bin directory? "You should notice that for security reasons the current directory is not in the $PATH variable and Linux does not look in the current directory to see whether a specific command is available from that directory. " Red Hat® RHCSATM/RHCE® 7 Cert Guide by Sander van Vugt
    – alsadk
    Nov 7, 2018 at 8:06
  • 1
    That just means it normally doesn't look in the current directory (contrary to Windows, which does).
    – Glorfindel
    Nov 7, 2018 at 8:07
  • So linux doesn't look in current directory unless its in $PATH, am I right?
    – alsadk
    Nov 7, 2018 at 8:32
  • 2
    Yes, and if . is in $PATH it will always look in the current directory.
    – Glorfindel
    Nov 7, 2018 at 8:32
  • I am not a root user, still . is not present in the PATH variable in my case(CentOS7) Jun 26, 2023 at 14:03
1

This other answer is good but the discussion in comments indicates a broader explanation may be useful.

This document describes in what sequence a POSIX-compliant shell should search for commands. It's very generic, not the easiest thing to understand. Instead of analyzing this highly abstract procedure, let's see how a real shell acts.

Assuming

  • your $PATH looks like this: /usr/local/bin:/usr/bin:/bin;
  • you're in Bash;
  • you type ls and hit Enter;
  • there's not ls alias that would change the command into something else than ls;

then Bash will run the first existing ls object from the list below. It's this list tailored to your case.

  1. ls function.
  2. ls builtin (usually ls is not a builtin in Bash; but since Bash can dynamically load new builtin commands, you can make ls a builtin).
  3. ls executable with its full pathname stored in a hash table (this will happen if sometime in the past the ls executable was found according to the next point and it's still remembered).
  4. ls executable from $PATH. In your case the sequence is:
    1. /usr/local/bin/ls
    2. /usr/bin/ls
    3. /bin/ls

Note there is no ./ls in the procedure; nor at any point your current working directory is taken into consideration, especially it's not matched against entries in $PATH.

Now this statement

Linux does not look in the current directory to see whether a specific command is available from that directory

only means there is no ./ls hardcoded in the above list. It would appear on the list if your $PATH contained . but

for security reasons the current directory is not in the $PATH variable

I will explain these reasons later in the answer. Still you can add . to your $PATH on your own. In this case ./ls would appear on the list as 4.x entry. Compare it to Windows which would look for ls in the current working directory regardless of whether it's in $PATH or not. If Linux did the same, then there would always be ./ls entry hardcoded somewhere above the point 3 of our list.

If your current working directory is /usr/bin and the list says ls should resolve to /usr/bin/ls, then it's technically the same executable than ./ls but

  • the shell never uses the literal ./ls path, the procedure yields /usr/bin/ls;
  • the fact you're in /usr/bin means nothing;
  • the fact /usr/bin is in $PATH means a lot.

But if you had . as the first entry in your $PATH then

  • the shell would use the literal ./ls path;
  • the fact you're in /usr/bin would mean a lot;
  • the fact /usr/bin is in $PATH would mean nothing.

In both cases it's the same executable that runs at the end of the day, but the shell gets to it in different ways.

It's also worth noting that statements like "my current working directory is in my $PATH" or "I'm in a directory that's in my $PATH" don't tell the whole story. They could mean:

  • "/some/particular/directory is in my $PATH and I'm in /some/particular/directory at the moment"

or

  • "the literal . entry is in my $PATH".

As shown, the two cases differ.


It looks like you expected ls not to be found just because you happen to be in its directory. Well, this would be inconvenient while there would be no security advantage whatsoever. The main security reason for not having . as a fixed step in a general command search sequence and for not having . in $PATH are explained in this UNIX FAQ:

Consider what happens in the case where . is the first entry in the PATH. Suppose your current directory is a publically-writable one, such as /tmp. If there just happens to be a program named /tmp/ls left there by some other user, and you type ls (intending, of course, to run the normal /bin/ls program), your shell will instead run ./ls, the other user's program. Needless to say, the results of running an unknown program like this might surprise you.

There is no point of prohibiting /usr/bin/ls only because you're in /usr/bin. If ls there is malicious, you probably have run it already while working in another directory, or you will run it eventually while working in another directory.


tl;dr

To summarize, ls in your example works because it's /usr/bin/ls that is found, not ./ls. The fact that the latter path resolves to the former one doesn't matter because the latter path is not used in the first place. It's not used because "Linux does not look in the current directory…" (meaning it does not look in .). It does look in /usr/bin nevertheless, because it's in your $PATH.

You must log in to answer this question.

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