62

The unix read permission is actually the same as the execute permission, so if e.g. one process has write access it's also able to execute the same file.

This can be done pretty easily:First this process has to load the content of the file,which shall be executed, into a buffer. Afterwards it calls a function from a shared library which parses the ELF in the buffer and loads it to the right addresses(probably by overwriting the old process as usual, when calling execvp). The code jumps to the entry point of the new program and it's being executed.

I am pretty sure Dennis Ritchie and Ken Thompson were aware of that issue. So why did they even invent this permission, what is the intention behind it and what's the sense of it, if it can't prevent any process of any user having read access from executing? Is there even such a sense or is it superfluous?

Could this even be a serious security issue, are there any systems, which rely on the strength of rw- or r-- permissions?

Martin Erhardt
  • 723
  • 1
  • 5
  • 9
  • 36
    An important point is that _all_ methods of bypassing -x will ignore the elevated privileges (setuid bit, file capabilities, path-based rules) that the original program has. – user1686 Sep 02 '14 at 05:27
  • 2
    I am astounded at the voting, etc. here. The only correct answer is a comment. – Joshua Sep 03 '14 at 02:06
  • 1
    Why would I go out of my way to execute a file which I don't want to execute? – jjanes Sep 03 '14 at 02:28
  • 1
    jjanes Well I thought it would be some kind of security issue, if users are able to execute programs they are not allowed to. – Martin Erhardt Sep 03 '14 at 06:20
  • 1
    @MartinErhardt: It only becomes a security issue if the program can _do more_ than the user could normally do through other methods. For example, Wireshark installs `/usr/bin/dumpcap` with elevated privileges (setuid bit or the `cap_net_raw` privilege), so by executing it a user could do stuff (capture network traffic) which the OS would not permit directly. Of course only members of the 'wireshark' group have the +x permission; all other users can only read the program. – user1686 Sep 04 '14 at 18:04
  • 1
    @MartinErhardt: You might find [these Old New Thing posts](https://www.google.com/search?q=site%3Ablogs.msdn.com%2Fb%2Foldnewthing%2F+airtight+hatchway) interesting, specifically [this](http://blogs.msdn.com/b/oldnewthing/archive/2009/04/09/9539191.aspx) or [this](http://blogs.msdn.com/b/oldnewthing/archive/2008/05/16/8510192.aspx), with examples of things that look like security issues, but don't really let you do anything more than normally. – user1686 Sep 04 '14 at 18:09

6 Answers6

80

There's an even easier way to bypass the "execute" permission: copy the program into a directory you own and set the "execute" bit.

The "execute" permission isn't a security measure. Security is provided at a lower level, with the operating system restricting specific actions. This is done because, on many Unix-like systems (especially in the days of Ritchie and Thompson), it's assumed that the user is able to create their own programs. In such a situation, using the "execute" permission as a security measure is pointless, as the user can simply create their own copy of a sensitive program.

As a concrete example, running fdisk as an unprivileged user to try to scramble the hard drive's partition table:

$ /sbin/fdisk /dev/sda 

Welcome to fdisk (util-linux 2.24.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

...

Changed type of partition 'Linux' to 'Hidden NTFS WinRE'.

Command (m for help): w
fdisk: failed to write disklabel: Bad file descriptor

That last line is fdisk trying to get a "write" file descriptor for the hard drive and failing, because the user I'm running it as doesn't have permission to do that.

The purpose of the "execute" permission is two-fold: 1) to tell the operating system which files are programs, and 2) to tell the user which programs they can run. Both of these are advisory rather than mandatory: you can create a perfectly functional operating system without the permission, but it improves the user experience.

As R.. points out, there's one particular case where the "execute" permission is used for security: when a program also has the "setuid" bit set. In this case, the "execute" permission can be used to restrict who is permitted to run the program. Any method of bypassing the "execute" permission will also strip the "setuid" status, so there's no security risk here.

Mark
  • 34,390
  • 9
  • 85
  • 134
  • 4
    Note `bash script.sh` does not need execute permission on `script.sh`. The file is just read by the shell, technically. – Volker Siegel Sep 02 '14 at 09:11
  • Volker Siegel more precisely the shell forks itself and dup2s the script file given as argument to 0, if there is execute permission and no ELF magic. – Martin Erhardt Sep 02 '14 at 12:58
  • So the most important purpose in practice of the execute permission today is to tell the shell that one file is a executable script, tough it cannot be executed like binary with execve. – Martin Erhardt Sep 02 '14 at 13:03
  • While another important purpose is to set execute permission without read permission to prevent users from reading or copying the binary, as Guntram Blohm stated. – Martin Erhardt Sep 02 '14 at 13:10
  • 4
    The execute bit also allows you to make a file with the `setuid` bit readable without allowing the user to run it as the file owner. I'm not sure why you would want to do that, but it acts as a security measure in that case. – Aaron Dufour Sep 02 '14 at 15:30
  • 4
    @AaronDufour: You can have `setuid` process executable by group and not others. – Jan Hudec Sep 02 '14 at 22:14
  • 5
    Actually the use of the execute permission with setuid is perhaps the most important use of the +x bit. It's unfortunate that the accepted answer doesn't even mention it. – R.. GitHub STOP HELPING ICE Sep 02 '14 at 22:41
  • @R.., is there any purpose to having a file with the setuid bit but *not* the execute bit? – Mark Sep 02 '14 at 23:13
  • 1
    @Mark: There are multiple execute bits: user, group, and world. As Jan Hudec noted, it's very common practice to make setuid binaries which are executable only by a particular group. Of course on a system with ACLs you could also use an explicit ACL to control who has +x permission. – R.. GitHub STOP HELPING ICE Sep 02 '14 at 23:25
  • Well Simon Richter pointed that allready out in our sudo discussion below, but it's good to have it in the concluding accepted answer, because it seems to be a very important purpose of that permission. – Martin Erhardt Sep 03 '14 at 06:25
  • @JanHudec I intended to imply that as the useful case. The votes make it clear I miscommunicated, so thanks for making that explicit. – Aaron Dufour Sep 03 '14 at 18:58
  • 1
    "Any method of bypassing the "execute" permission will also strip the "setuid" status, so there's no security risk here." - This is true, but unimportant, since the user making the copy can re-set the `setuid` bit. The important thing is that the copy is owned by a different user (namely, the copying user), so even with the `setuid` bit set, it does not allow that user to execute it as the original file owner. – Aaron Dufour Sep 03 '14 at 19:03
  • As Helfire just pointed out execute permission can be quite important in terms of security, because a missing one prevent users changing into a directory. – Martin Erhardt Sep 03 '14 at 19:24
  • It would be nice if you could enumerate all these use cases in your top answer(1., 2.). – Martin Erhardt Sep 03 '14 at 19:28
  • 1
    I didn't cover +x as applied to directories because the question was about +x as applied to files. – Mark Sep 03 '14 at 22:51
27

You can set the execute bit, but not the read bit, on an executable file. That way, noone will be able to copy the file, but people can execute it anyway.

This is quite pointless today, because a) it works for compiled programs only, not with scripts (on most systems); b) these days, with 90% of all unixes being linux, people can copy executables from just about anywhere, and c) the disk space a copied executable takes doesn't really matter.

Still, there were uses for that in the old days.

The Unix system i used at school, 30 years ago, was very limited in RAM and Disk space. Especially, the /usr/tmp file system was very small, which led to problems when someone tried to compile a large program. Of course, students weren't supposed to write "large programs" anyway; large programs were typically source codes copied from "somewhere". Many of us copied /usr/bin/cc to /home/<myname>/cc, and used dd to patch the binary to use /tmp instead of /usr/tmp, which was bigger. Of course, this just made the problem worse - the disk space occupied by these copies did matter those days, and now /tmp filled up regularily, preventing other users from even editing their files. After they found out what happened, the sysadmins did a chmod go-r /bin/* /usr/bin/* which "fixed" the problem, and deleted all our copies of the C compiler.

Another use is to tell the shell which files are intended to be executed and which aren't. You don't want a a random text file executed because you typed its name; the x bit provides a way to prevent this. (These days, the shell could just look at the start of the file, and only execute it if it starts with #!, but this was introduced much later). bash's completion feature, as well, will suggest files with executable bits only when you're typing a command.

Guntram Blohm
  • 1,529
  • 11
  • 13
  • The File beginning with "#!" is called shebang isn't it? – Martin Erhardt Sep 02 '14 at 12:54
  • 1
    Shebangs only state what interpreter shall be used to interprete, they don't tell the shell that the program is a script at all and can be executed, tough it can't be executed by the OS using exec*. So the execute permission is still necessary in this case. – Martin Erhardt Sep 02 '14 at 13:22
  • Yes, I always grant [Noone](http://en.wikipedia.org/wiki/Peter_Noone) read permissions on the systems I manage, at the least. – Garrett Albright Sep 02 '14 at 21:09
  • And the accidental execution problem was made worse by the fact that in those days, it was considered normal to have `.` in `$PATH`, so programs in the current directory could be executed by typing their names without a `./` prefix. –  Sep 03 '14 at 00:20
  • Note that shells (and execvp(), env, xargs, find -exec...) are _meant_ to execute executable text files with no `#!` with `sh`. Actually that's the only way to execute scripts that is specified by POSIX and the Unix specification. Note that on Linux, `.` is still in front of the default PATH you get (for execvp()) when the PATH env var is not set. – Stéphane Chazelas Sep 03 '14 at 09:30
  • Couldn't you attach a debugger to the process or even start the executable with `LD_PRELOAD` and dump the core image from there, even if the read bit isn't set? – forest Dec 24 '19 at 05:44
7

There is a readymade way to execute an arbitrary file: pass it as an argument to the dynamic linker (which is the appropriate interpreter for a dynamically loaded executable). E.g. under Linux,

cp /bin/ls /tmp/
chmod -x /tmp/ls
/lib/ld-linux.so.2 /tmp/ls

However, this comes with the same restriction as reading the file and jumping to code: the setuid bits are not evaluated.

In the old days, we'd often have binaries like /bin/su:

-rwsr-xr-- root wheel  ...  /bin/su

Only members of the wheel group, which the sysadmins kept trimmed to people knowing the root password would even be able to execute the su command, so even if a buffer overflow existed in that binary, allowing callers to bypass security, the exploit would be usable only by people who know the password anyway.

Simon Richter
  • 1,482
  • 11
  • 8
  • I know this wheel thing since I configured archlinux the first time. One thing I don't understand about your question is, why there is a need of some buffer overflow in su to be executed. I thought it can be easily executed be every user using the dynamic linker method mentioned above? – Martin Erhardt Sep 02 '14 at 16:49
  • 4
    Yes, but it would be executed without setuid, as the calling user, making it worthless for the attack. – Simon Richter Sep 02 '14 at 17:00
6

I'm surprised no one else has referred to another use of +x bit: directories. Maybe you are after execution of (example) something in /bin (shell script or otherwise), but there is more to execute bits than files (of course, a directory IS a file but it is a different kind of file).

If you have +x access on a directory but -r on that same directory, then you'll have the following capabilities:

  • If you know the name of a file (or directory) in that directory, you can list it (e.g., ls on it). You must know the name, however.
  • You cannot change in to it (via cd command or the chdir system call).

If however, you have -x and +r, you can do the following:

  • You cannot change to the directory (same way as above).
  • You can list the files. But since you don't have +x access to the directory, you cannot access the files themselves.
  • This also means you cannot update (timestamp only or otherwise) and neither can you open them in a text editor (or cat, or ...).

If you have +rx then you can do all of that (except that you need +w to write to the directory itself which is to say make new files; editing files works, removing does not, creation does not)

And yes, this means it is possible to have some people view or edit files but only if they know the exact path to it (as long as they have the rights to edit, anyway). And yes: ls is list and that goes for searching directories. So in summary: executing a directory is changing to it (for whatever reason). Of course the bits all together is what really matters.

4

If you for some reason want to keep the binary code secret, you can make the program executable without being readable. This is not useful if those users have physical access to the machine. It is also not useful if the source or binary code is widely available. So this is a fairly limited use case.

If the program has a setuid or setgid bit, execute access does something more, than what can be achieved by reading the binary. One approach is to create a setuid executable which is only executable to a specific group. If it was world readable, people outside that group still couldn't copy it and make use of the setgid bit on the original executable. (Though in most cases I would rather use setgid than setuid, and then use the group on the directory to control who can access the executable.)

Usually the executable bit is simply used to indicate which files are programs in the first place. That way completion can work better, and you don't execute unwanted executables by accident.

If you want to prevent users from copying an executable and running it, you can mount home directories with noexec. In order for this to make sense, you have to use noexec to every file system, where the user could write anything.

kasperd
  • 5,402
  • 1
  • 19
  • 38
  • 1
    This is also not useful if the user knows how to use a debugger. – Nate Eldredge Sep 03 '14 at 01:09
  • 1
    @NateEldredge Obviously only root has permission to attach a debugger to a suid or sgid executable. If you attach the debugger before executing the executable, suid and sgid is simply ignored. If you execute the suid or sgid executable first and try to attach a debugger later, the executable won't be allowed to attach. For files without read permissions, the situation is less clear cut. – kasperd Sep 03 '14 at 07:29
  • 1
    @NateEldredge For a running executable which you do not have read permissions on, attaching a debugger is not permitted. But if you attach a debugger first and then execute an executable which you have permission to execute but not read, it does get executed. But this means the debugger could trivially access all the pages mapped from the executable. This seems like a clear violation of the lack of read permissions. Is this a bug, or is it specified by some standard? – kasperd Sep 03 '14 at 07:32
  • http://unix.stackexchange.com/questions/153471/tracing-executable-without-read-permissions – kasperd Sep 03 '14 at 07:59
  • *No* security measures are useful if the user has physical access to the machine. Well, I mean they're useful to keep honest people honest (like a padlock on an easily-breakable gate) but if someone really wants to get in it won't stop them. But that's true of all technical security measures, not just `-r +x`. – flarn2006 Sep 20 '16 at 02:05
2

The execute bit permission is checked by the kernel on executing the exec(2) (and cousins) system call. You will need it only to execute programs at the kernel level.

Only programs with that bit on (whichever hits to you as the owner, group or others is what is being checked) can be exec()ed by the kernel.

Other different thing is what the shell does when interpreting a shell script or perl, or whatever interpreter may you have. On scripts, the kernel checks the #!... at the beginning of the file as a magic number, and launches the shell indicated there (you will need execute permission for the shell also), and you do need read permissions on that script, as the shell has to open it and read it to be interpreted. For shell scripts you'll need read permission as well as executing permission. But for shell scripts you only need read permission, as you always are able to execute a shell script by executing the shell and passing the shell script as a parameter (or input file)

Of course, as it has been pointed to, the execute bit can be circunvented by copying the program and making it executable, but you'll not be able to copy it if you don't have read permissions to make that copy (you continue to be able to execute it).

Try to change (as root of course) permissions to ls(1) and make it 0111 (---x--x--x) and try to do an executable copy of it, and see how you cannot get your executable copy, even when you continue to be able to execute it.

On directories, execute bit means a different thing. The kernel uses 'x' permission when iterating through the path (in the namei() kernel function) so if you don't have execute permissions on a directory, you cannot either use it, nor the files accessible through it. Even you can read a directory contents with read permissions, but you cannot access the files in it. Or at the opposite, you can have execute permissions on a directory but not read access, and you'll be able to use the files inside, but you'll not be able to see the directory contents.