63

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?

6
  • 37
    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 2, 2014 at 5:27
  • 2
    I am astounded at the voting, etc. here. The only correct answer is a comment.
    – Joshua
    Sep 3, 2014 at 2:06
  • 1
    Why would I go out of my way to execute a file which I don't want to execute?
    – jjanes
    Sep 3, 2014 at 2: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. Sep 3, 2014 at 6: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 4, 2014 at 18:04

6 Answers 6

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.

15
  • 4
    Note bash script.sh does not need execute permission on script.sh. The file is just read by the shell, technically. Sep 2, 2014 at 9:11
  • 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. Sep 2, 2014 at 15:30
  • 4
    @AaronDufour: You can have setuid process executable by group and not others.
    – Jan Hudec
    Sep 2, 2014 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. Sep 2, 2014 at 22:41
  • 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. Sep 2, 2014 at 23:25
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.

6
  • The File beginning with "#!" is called shebang isn't it? Sep 2, 2014 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. Sep 2, 2014 at 13:22
  • Yes, I always grant Noone read permissions on the systems I manage, at the least. Sep 2, 2014 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.
    – user54862
    Sep 3, 2014 at 0: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. Sep 3, 2014 at 9:30
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.

2
  • 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? Sep 2, 2014 at 16:49
  • 4
    Yes, but it would be executed without setuid, as the calling user, making it worthless for the attack. Sep 2, 2014 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.

5
  • 1
    This is also not useful if the user knows how to use a debugger. Sep 3, 2014 at 1: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 3, 2014 at 7: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 3, 2014 at 7:32
  • 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, 2016 at 2: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.

You must log in to answer this question.

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