2

Someone asked a question on Ask Ubuntu about why they got permission denied when they entered in a Bash shell

/etc/profile

I know this is because the file has no execute permission. Even root cannot execute it (sudo /path/to/file/with/no/execute/bits fails with the uninformative error sudo /path/to...: command not found). I also know that root can enter a directory with no execute bits, so the absolute prohibition on executing non-executable files seems special. In chat, Eliah Kagan opined that the reason root would not be able to execute non-executable files was to protect root (presumably, from accidentally executing dangerous code).

I briefly wondered why anyone would want to execute /etc/profile and thought that if anyone did want to execute it, they would probably actually want to source it (because it is a configuration file that sets environment and shell variables). I then realised that execute permission is not needed to source any regular file. But source executes the file in the current shell! The file can contain any command, and . file will go right ahead and execute it.

If execute permission is restricted to prevent accidental execution of potentially dangerous code, why is it possible to execute non-excutable files using the source command?

Zanna
  • 3,571
  • It's difficult to interpret a deliberate action like typing . /etc/profile as "accidental". it's your responsibility to not burn out your remaining eye with the laser pointer. – cas Jan 25 '18 at 13:21
  • 1
    Because POSIX says "Unlike normal command search, however, the file searched for by the dot utility need not be executable." A proper answer should probably discuss this and compare POSIX . with source in bash. – Kusalananda Jan 25 '18 at 13:22

1 Answers1

4

I don’t think executing a non-executable file fails on purpose to prevent accidental execution of potentially dangerous code. It’s just part of the semantics of execve: it fails with EACCES if “Execute permission is denied for the file or a script or ELF interpreter.” (I’m quoting from the Linux execve manpage. POSIX says something similar: “Search permission is denied for a directory listed in the new process image file’s path prefix, or the new process image file denies execution permission.”) Unix/Linux has never been particularly concerned with preventing users from blowing their own feet off.

I think the explanation is rather more prosaic: the specifications for execution and sourcing are different. Direct execution asks the kernel to execute a given command, and that enforces execution privileges. Sourcing a file is just specified as reading it and executing it; in fact the bash manpage explicitly states that “The file searched for in PATH need not be executable.” POSIX says “Unlike normal command search, however, the file searched for by the dot utility need not be executable.” (. is equivalent to source.)

Note that you can execute binaries even when they’re not executable, using a technique similar to sourcing them:

$ cp /bin/ls .
$ chmod 644 ls
$ /lib64/ld-2.26.so ./ls

Kusalananda’s point about comparing bash’s source and POSIX . is interesting. In non-POSIX mode, if source is given an argument without a path, it tries to find it in the PATH, and if it doesn’t find it, looks in the current directory; in POSIX mode it doesn’t, because POSIX forbids this:

Some older implementations searched the current directory for the file, even if the value of PATH disallowed it. This behavior was omitted from this volume of POSIX.1-2008 due to concerns about introducing the susceptibility to trojan horses that the user might be trying to avoid by leaving dot out of PATH.

That doesn’t really change much in the discussion at hand though since an argument with a path will be processed by source or . in any case. (And really you should always use a path, even if only relative, for source arguments, to avoid surprises when you try to source something which is also on your PATH. Try creating a file named test and sourcing that with source test in bash to see what I mean.)

Stephen Kitt
  • 434,908