Unix file permissions
This article provides an introduction to traditional UNIX permissions available on a GNU/Linux machine and explains the intricacies of setting permissions properly using advanced Access Control Lists (ACL's).
On a shared web hosting GNU/Linux based server there are many unrelated user accounts. Under this type of environment, it is important to set permissions properly in order to prevent users from accidentally or maliciously interfering/viewing the data of other users, whilst still allowing services like apache access to the data that they need.
The test system used for this article is running Red Hat Enterprise Linux ES 3 on x86.
There are 3 permissions available in Linux:
On a file, the permissions pretty much do what they say:
Read permission allows reading the file data <!plus fcntl(2) read locks and flock(2) locks>.
Write permission allows writing to the file <!plus fcntl(2) write locks and flock(2) locks>.
- Execute permission on a file allows the file to be loaded and executed by the kernel.
On a directory, the interpretation of the permissions are slightly different:
- Read permission allows a directory listing.
- Execute permission allows access to the directory (eg chdir(2) into it, stat(2) on the directory entries).
- Write permission allows the creation/deletion of directory entries (files, links, directories, etc). This must be combined with execute permission though - write permission by itself confers no rights.
Permission names can also be abbreviated: 'r' for Read, 'w' for Write, and 'x' for eXecute. Thus a permission of rwx means 'Read, Write, and Execute'.
Permissions are also often represented numerically in octal (base 8):
- Read has the value of 04
- Write has the value of 02
- Execute has the value of 01
A set of permissions can then be represented by simply adding up the numbers. For example the octal permission value of 05 means read and execute access.
Traditional Linux ACL's
Each object (files, directories, etc) in Linux has an user identification (UID) and a group identification (GID). For example:
[pawn@juggernaut pawn]$ touch new_file [pawn@juggernaut pawn]$ ls -ln new_file -rw----r-- 1 10000 100 0 Mar 12 12:21 new_file [pawn@juggernaut pawn]$ ls -l new_file -rw----r-- 1 pawn users 0 Mar 12 12:21 new_file
In the above example the file new_file has a numeric UID of 10000. From the password database, this corresponds to the user name of pawn as shown in the third command. The file has a numeric GID of 100. This corresponds to the group name users.
Access to objects (files, directories, etc) in Linux is controlled by 3 sets of permissions. These are:
- Permissions for the user (owner)
- Permissions for a member of the group
- Permissions for "others" (ie. everyone else)
As you may have guessed from the previous example the permissions of the file new_file are listed in the first column of the ls -l output.
The first character in the output - indicates the type of object. A plain hyphen indicates that this is a regular file.
The next 3 characters rw- indicate the permission for the owner of the file (ie. user "pawn"). In this example the user permissions are read and write (but not execute).
The next 3 characters --- indicate the permission of members of the group "users". In this case the members have no permission to the file.
Finally the last three characters r-- indicate that all other users have read access.
Like the individual permissions, the 3 sets of permissions can also be represented numerically in octal. Using the example file above, the permissions would be represented as 604.
- The 6 means user 4 (read) + 2 (write).
- The 0 indicates no permissions for group.
- The 4 (read) means read only for all others.
Permissions can be altered via the command line utility chmod. Run man chmod from the command line for details. The manual for the chmod utility also details some extra permission bits (setuid, setgid, sticky) which will not be covered in this article.
Order of permission checking
When deciding whether a process can access an object the order of the checks is:
- If the file system is mounted read-only or the file is marked as immutable then write access is DENIED.
- If you have super user privileges (ie appropriate capabilities) then access is ALLOWED.
- The file owner UID is then checked against the file system UID of the process. If they match, then:
- If the requested level of access (read/write/execute) is allowed, then access is ALLOWED
- otherwise access is DENIED
- The file group GID is then checked against the file system GID and the auxiliary groups list of the process. If there is a match, then:
- If the requested level of access (read/write/execute) is permitted by the group permissions, then access is ALLOWED
- otherwise access is DENIED
- Finally the desired level of access (read/write/execute) is checked against the "others" permission set, and access either allowed or denied.
Protecting shared hosting users
In our shared hosting scenario as outlined in the introduction, we would like the Apache httpd server (running as user apache) to be able to access the public files of our user pawn. We don't want other users on the system to be able the files of the user pawn though. So how can we do this?
Why, through the power of negative ACLs! From the permission checking order section above, we see that if a user is a member of the group that the file GID is set to, then the permission that will apply to them is whatever is set for the group. The "other" permission set will never be checked!
This means that in our example, another user who is a member of the group "users" will NOT be able to access the file, whilst the user "apache" will be able to access the file due to the "others" permission set.
Thus to ensure that users cannot access each others files:
- The initial permissions on a user's home directory should be set to 0701
The umask needs to be set to 072 so that new files are created with the correct permissions
The umask lists the permissions which get cleared out on new file creation.
- The 0 means that none of the user permissions are cleared.
- The 7 means that ALL group permissions get cleared.
- The 2 means that the write permission of others gets cleared.