The 'r' bits affect opening a file for reading. Even if you don't have read permission you can still "stat" a file, i.e. find out about its size, owner, modification time, etc.
The 'w' bits affect opening a file for writing. (But note that if the directory containing a non-writable file is writable, you can still remove the file, rename another file to the same name, etc.)
The 'x' bits determine whether the file is executable. Binaries can be executed even if you can't read them; but this is not true of scripts, since the interpreter needs to be able to open the script for reading.
The 's' or 'S' bits are the "setuid" and "setgid" bits. ls uses 's' to indicate a setuid or setgid bit with a matching execute bit and 'S' where the corresponding execute bit is missing.
The effect of running an executable with a setuid bit is to change the effective user ID of the process to the user that owns the file; similarly the setgid bits causes the effective group ID of the process to be set to the group of the file. (In practice there are some other effects, for instance coredumps are disabled and the C library may ignore or delete some environment variables; both are to make the setuid/setgid feature less horrendously insecure.) It's very easy to accidentally create a security hole with these features.
For example, the passwd program typically needs to update a system-wide password file, which ordinary users should not be able to modify. Thus the executable is owned by root and has its setuid bit set; it runs with an effective user ID of root, which is able to modify the password file.
Similarly, games are sometimes made setgid to the "games" group, which is used to control write access to high score files and other such administrivia.
The sticky bit, 't' or 'T', is widely ignored on ordinary files (but see below).
The 'r' bits determine whether you can get a list of filenames within a directory. They don't affect access to files in the directory.
The 'w' bits affect the following operations:
...and so on: anything that involves changing the contents of the directory.
Notice that it is the 'w' bit on the containing directory that determines whether a file can be deleted, not the 'w' bit on the file itself.
The 'x' bits affect looking up names in a directory (for instance, to open them) and also "cd" to the directory; officially this is called the "search" permission. So to access files within a directory you need 'x' permission on it, plus whatever permissions on the files themselves are relevant to the operation you wanted.
Directory permissions lead to some odd effects.
If you have 'r' but not 'x' on a directory then you can list the files in the directory but not access them in any way. Trying to do a plain "ls" on such a directory will work (except possibly unless you've aliased ls to include extra flags); trying to do "ls -l" will produce a "Permission denied" error for each file in the directory.
Conversely if you have 'x' but not 'r' then you will not be able to list the files in it, but if you happen to know their names then you will still be able to access them, and you will be able to "cd" into the directory.
The setgid bit, 's' or 'S' if there is no corresponding group 'x' bit, influences the creation of new files in the directory. New files are created with their group ID set to that of the directory; the same is true of new directories but in addition they have the setgid bit set. (Not all systems do this.)
The point of this is to make working with groups easier. If all the files created in a group's working directory automatically have the right group ID then other members of the group will be able to access them provided they are created with the right permission bits. The latter can be fixed manually, but it is more convenient to set each user's umask to 002 or 007 (to make all new files group writable). Each user needs to have their own private group, sharing name and number with their user ID, to avoid having to constantly change umask (or leaving all their private files accessible to whatever their default group is).
The setuid bit is widely ignored on directories (but see below).
The sticky bit, 't' or 'T', affects changes to names in directories. You cannot remove or rename over a file in a sticky directory unless you are the owner of the file. This is used to make /tmp less insecure (though it still requires extreme caution to use safely).
If the effective user ID of the process matches the user ID of the file, then the 'user' bits are used, even if the 'group' or 'other' bits are more liberal.
Otherwise if the effective group ID of the process, or any of the supplementary group IDs, matches the group ID of the file, then the 'group' bits are used, even if the 'other' bits are more liberal.
Otherwise the 'other' bits are used.
So, for example, permissions of ---r-xr-x allow read and execute to everybody except the file's owner.
These restrictions don't apply to the superuser (effective user ID 0, or root), who can access any file or directory in any way, with the exception that they can only execute files with at least one 'x' bit. The setuid and setgid bits still have their usual effects.
The error return you get when you attempt something prohibited by file permissions is EACCES or "Permission denied"; this should not be confused with EPERM or "Operation not permitted".
For instance trying to cat a file that you don't have read permission on results in "Permission denied". But trying to chown one of root's files to yourself results in "Operation not permitted" - no possible combination of file permissions would allow you to do this, the rule is enforced without taking them into account.
Some platforms have an additional concept of access control lists.
Some platforms, e.g. Linux, have a separate filesystem user ID and group ID for each process, which normally follow the effective user ID and group ID but can in principle be set to other values.
Some platforms act as if all directories were setgid. Others allow this behaviour as a mount option.
Some platforms used the setgid bit on non-group-executable files to enable mandatory record locking.
Some platforms, e.g. FreeBSD, optionally take note of the setuid bit on a directory: any files or directories created in that directory use the directory's user ID as their user ID and new directories have the setuid bit turned on.
Some platforms will refuse to put a sticky bit on non-directories. For instance FreeBSD returns EFTYPE in this situation.
Older versions of HP-UX used the setuid bit on directories to mark context dependent files. When the name of the directory was accessed, instead of getting the directory you would get one of the files within it, chosen by comparing the filenames with bits of per-process information.
Older versions of UNIX used the sticky bit to prevent the object code of an executable being immediately discarded when all the processes running it terminated, allowing very rapid startup if the executable was run again. Modern platforms would be expected to do more or less the same thing for every executable.
Please let me know if you know of any other variations.
Copyright © 2004 Richard Kettlewell
RJK | Contents