Open source software security

Linux Permissions

30 November -0001
Justin Klein Keane
Feb. 4, 2007

Linux Permissions

Linux security permissions are governed by the aggregation of two separate concepts - the entity requesting to work on the data and the permissions granted to that entity. There is a finite set of entities and a finite number of permissions. By checking entity permissions the system determines whether or not to allow certain actions to occur.

In Linux permissions may be set on directories (folders) or files. Permissions of files are slightly different than they are for directories, but their representation is always the same. Doing a directory listing in the long format (ls -l) will quickly reveal permissions on files and sub-directories. These permissions are represented with a series of letters preceding the user name, the group name, and the filename. These letters are d, r, w, x, t, and s (or S). We'll go over the meaning of each of these in a moment but first let us examine the actors in a Linux system.

On a Linux system every user belongs to three categories. These are the user account, the group account, and everyone not covered by the user or group, called 'others.'

User Accounts

Every user on a Linx system is identified by their account. This is the username you log into the system using. A complete listing of user accounts can be found in the /etc/passwd file. Users have several attributes that are set upon their creation. These beginning attributes are all created according to the skeleton directory /etc/skel. For instance, if the administrator creates a file called .profile in the /etc/skel/ directory then all new users will have a copy of that .profile file in their home directory when they are created. Users are created and modified using the commands:

useradd
adduser
userdel
usermod

You can look at the manual pages for each command for more details. When a user is created they are assigned a username, a password, a numeric user id, a numeric group id, a descriptor, a home directory, and a login shell. The user numeric id is a unique identifier that the system uses when determining permissions. Note that each username on a Linux system _must_ be unique as well.

User accounts are described in the /etc/passwd file. This file can be read by everyone so you can take a look at it any time. The format is as follows:

justin:x:500:500:Justin Klein Keane:/home/justin:/bin/bash

The first entry is the user name, the second is the password (always 'x', we'll describe why in a moment), the user numeric id, the group numeric id, the user descriptor (in this case the full name), the user home directory, and the users' login shell.

The passwords are always listed with an 'x' because the passwords are actually stored in the /etc/shadow password file in an encrypted format. Although any process on the system can look at the passwd file, only the root user can actually examine the encrypted password files. This is a security enhancement that allows any user or process on the system to examine the valid users and groups on the system, but only the super user can look at (and validate) passwords.

Group Accounts

Each user account can be assigned to a group. Groups are delineated in the /etc/group. If you look at /etc/group you'll see rather cryptic entries like:

users:x:100:joe,bob,mary

This file contains one group per line, with group attributes delimited by colons. The first item in the list is the group name. The second is the password, and on modern systems this will always be represented using an 'x'. The reason for this is the same for the listings in /etc/passwd - to implement password shadowing. The next entry is the group id number. Each id number is unique. The final entry is a comma delimited list of user accounts that belong to the group. Users can appear in as many groups as you like. The relevant commands for groups on a Linux system are:

chgroup
chgrpmem
lsgroup
mkgroup
rmgroup

You can examine the manual pages for each command for specifics on how they work.

File Permissions

Now that we've examined the idea of users and groups lets examine file permissions. There are several basic permissions that can be set on any object in the Linux system. Objects are files or directories. Files can be anything from a program to a grocery list, but they are always physical pieces of code or data stored on the filesystem. Directories are storage structures, used to separate and catalogue files.

All permissions are broken down into three categories: those that apply to the user, those that apply to the group, and those that apply to others. The user is the owner of the file or directory. The group corresponds to one of the groups in the /etc/group file, and consequently those permissions apply to every member of that group. The others are everyone not covered in either the user or group definitions.

You will see the permissions laid out in a series of 10 single character entries when you examine permissions. The default for each of these entries is a dash. This indicates there is no specification.

The permissions are laid out in three groups of three. The first character is simply descriptive. It is set to 'd' if the entry is a directory, otherwise it is left as a dash. The format of the permissions is as follows:

duuugggooo

with the 'd' for directory, then three slots indicating the user permissions, three for the group permissions, and three for the other permissions.

The permissions that can be set on a file are: read, write, execute, setuid and setgid. Read indicates whether or not the entity in question can examine the contents of a file. Write indicates whether the requestor can alter or edit (including delete) the contents of the file. Execute only applies to programs and indicates that the requestor can run the program. Even though execute permissions can be set on a plain text file, they won't do anything.

The setuid (suid) and setgid (sgid) permissions are special. Their context is limited to programs. They indicate that when a program is executed it should run as the user (in the case of suid) or as the group (in the case of sgid). By default programs will run with the effective user id (euid) and effective group id (egid) of the user that initializes them. For instance, if there is a program that examines log files and creates new files and the user justin runs that program, the program will attempt to access the log files with the same permissions as justin, and any files the program writes will be created in the exact same way as if the user justin had created them by hand. By setting the user id or group id you can override this default behavior, so that the program can be executed by one user or group member, but runs as another user or group.

File permissions are represented in letter format. Read is represented as an 'r', write a 'w' and execute an 'e'. The suid and sgid are represented by an 's'. This is a lower case 's' if the execute permission is set, or a capital 'S' if the execute permission is not set. This is because the suid and sgid are represented where the execute indicator would normally be placed. For instance a file with the following permissions:

-rws--x---

Shows that the user has read, write and execute permissions, that the program is suid to that user and that all members of the group have execute permissions.

Directory Permissions

Directories have some of the same permissions although the permissions have slightly different meanings. In addition, directories have a sticky bit designation that does not apply to files. Directory permissions are specified for user, group and other in the same manner as are file permissions. Read permission means that the entity can list the directory contents. The execute permission means the entity can enter a directory or access the directory contents. The write permission indicates that the entity can add contents to the directory. The sticky bit is a little strange and indicates that only the directory own and root can actually delete anything in the directory regardless of other permissions.

The directory permissions can create some interesting challenges. A directory can be set up so that a user might not be able to see or list any files in a directory, but they might be able to execute some files in that directory. With the sticky bit you can also have a situation where a user could write files into a directory, but couldn't delete them.

You can also set the group id on a directory. Doing so will cause all new files created in the directory to inherit the group id of the parent directory. This will cascade as well, so new directories created in the directory will inherit the sticky group id.

Setting Permissions

Only a file owner and root can set or change permissions on a file or directory. Permissions can be set or modified using two main programs:

chmod
chown

Chmod changes the file or directory permissions while chown changes the ownership. You can use chmod in a number of ways the shorthand way is perhaps the easiest. In this manner you specify a plus or minus sign (depending on whether you wish to add or revoke a privilege) proceeded by the character indicating whether the change should apply to the user, group or other. More than one character can be specified. For instance:

chmod ug-w 

will revoke the write permission for both the user and the group. 's' is used for the set uid and set gid, and 't' is used for the sticky bit. For instance:

chmod g+s

will set the group id on the target and

chmod +t

will set the sticky bit for the target.

You can also use octal notation for file changes. In this system the permissions are represented by a series of four numbers. The first number is the suid, sgid or sticky bit indication, the second number is the user indicator, the third is the group indicator, and the last is the other indicator. The first number corresponds to the following layout:

------------------------------------------
| 0  |  Nothing
------------------------------------------
| 1  |  Sticky bit is set
------------------------------------------
| 2  |  Setgid is set
------------------------------------------
| 3  |  Setgid and sticky bit are set
------------------------------------------
| 4  |  Setuid is set
------------------------------------------
| 5  |  Setuid and sticky bit are set
------------------------------------------
| 6  |  Setuid and setgid are set
------------------------------------------
| 7  |  Setuid, setgid, and sticky bit set
------------------------------------------

In this schema you'll notice the sticky bit (value 1), the sgid (value 2) and setuid (value 4) always add up to form the correct permission. For instance, a value of 6 (4+2) indicates sgid and setuid, while a value of 3 (2+1) indicates the sticky bit and sgid are set.

The other permissions are set using the following designation:

------------------------------------------
| 0  |  No Permissions
------------------------------------------
| 1  |  Execute
------------------------------------------
| 2  |  Write permissions
------------------------------------------
| 3  |  Write and execute
------------------------------------------
| 4  |  Read
------------------------------------------
| 5  |  Read and execute
------------------------------------------
| 6  |  Read and write
------------------------------------------
| 7  |  Read, write, and execute
------------------------------------------

You can observe a similar pattern with read having a value of 4, write a value of 2 and execute a value of 1.

Using the combination of four number designations, the first for sticky/suid/sgid, the second for user, the third for group and the fourth for other you can create complex permissions quite tersely. For instance:

chmod 1660

Will set the sticky bit, give the user read and write, the group read and write and no permissions to others.

Umask

The concept of umask is basically to set default user behavior. If a user has a umask setting listed in their .bash_profile then all files and directories they create will conform to that format. For instance, if the umask is set to

0755

Then all files and directories created by the user will by default have read, write and execute for the owner, and read and execute for the group and others.

Nuances

File permissions are assigned in a hierarchical order. The system examines the file permissions starting with the user permissions, then the group permissions and finally the owner permissions. The privilege checking halts on the first match. This means that you could potentially have a situation where a file owner doesn't have read access to the file, but s/he is a member of the group that does have read access to the file. In this scenario the user would be denied read permissions since the first privilege set that matched was the user set. For instance, if the user bob is a member of the users group, given the following file:

-rw-r--r--  bob  users  somefile.txt

Bob can read and write to the file. If, however the permissions were altered to:

-r--rw-r--  bob  users  somefile.txt

Then bob couldn't write to the file. If the permissions were further changed to:

-r--r--rw-  bob  users  somefile.txt

bob couldn't write to the file but anyone not in the users group would be able to write to the file.

Problems

While the Linux permissions model allows for some very complex and robust permissions models it does fall short in several areas. Say, for instance you have a directory full of files that you want to share with the accounting group, and bob in marketing. This is tough since you can't make bob part of the accounting group, but without being the owner he won't be able to see any files. You can make a special group just for this directory that includes everyone in accounting plus bob, but you can see quickly how this is inefficient. You end up creating a lot of 'special circumstance' groups. Unfortunately there isn't any easy way to get around this problem in Linux. Using ACL (Access Control List) add on's you can overcome this issue, but that falls outside the scope of this article.