Filesystem Security

Vincent Danen

February 25, 2011

There are a number of different filesystems available for the different *NIX-ish operating systems. Linux has perhaps the largest variety of filesystem types, including ext2, ext3, ReiserFS, XFS, JFS, and more. Other systems such as FreeBSD are a little more conservative in what filesystem types they typically use, using one or possibly two filesystem types for the system, while giving users the option to read/write other filesystem types (ie. in a dual-boot situation).

Despite all of these different filesystem types, there are some common factors to each. Basic filesystem permissions are identical across the board. Some filesystems offer different features than others, for instance ext2/ext3 offer quota support whereas ReiserFS (currently) does not.

Unlike other operating systems, *NIX-ish operating systems use a system of permissions where files are concerned. This can be extended to include device support (hard drives, soundcards, etc.) because these devices are seen as special "files" to the operating system. Permissions can be modified on these devices as well.

The permissions granted to files or devices are ownership and access permissions. File ownership indicates what users and groups the file belongs to. Access permissions indicate what the owner and groups (and others) can do with these files, devices, and directories.

Permissions

If you look at any given file, using a long or extended listing format (ie. using "ls -l"), you will see a set of symbols before each file. There are ten characters that symbolize permissions for each file. The first character represents the "special" file type, and can include:

  • - - a normal file
  • b - a block device, like a hard drive
  • c - a character device, like a serial port or sound card
  • d - a directory
  • l - a symbolic link
  • s - a UNIX socket file (BSD or SVR4)
  • = or p - FIFO (Linux, System V)

The next three characters represent user permissions, ie. what the user who owns the file has permission to do with it. The following three represent group permissions, ie. what the group who owns the file has permission to do with it. the final three represent "others", those who are neither the user nor the group.

$ ls -al
total 488
drwxr-xr-x   93 vdanen   staff        3162 Mar 23 23:22 ./
drwxr-xr-t    5 root     wheel         170 Jan  7 01:02 ../
-rw-r--r--    1 vdanen   staff        5568 Mar 23 23:22 .procmailrc
-rw-------    1 vdanen   staff      487428 Mar 23 23:22 nokia.mpeg
drwxr-xr-x    2 vdanen   vdanen         68 Mar 23 23:22 temp/

The above is a cut-down example of using the ls -al command in a home directory. You see here a good mix of different files.

  • The first (./)indicates the current directory, and you can see that it is a directory owned by the user vdanen and the group staff. vdanen has read/write/execute permissions, the group staff has read/execute permissions, and other users had read/execute permissions (which is a prime example of bad security, actually). * The second (../) indicates the parent directory, and you can see that is also a directory, owned by root and the group wheel. It also has the sticky bit set, indicated by the t in the "other execute" field (more on this in a moment).
  • The third is a "hidden" file (.procmailrc). It won't show up in normal directory listings. This file is however owned by user vdanen, group staff. vdanen has permission to read and write to this file, and everyone else has permission to read it. * The fourth is a regular file (nokia.mpeg) that is also owned by user vdanen, group staff. This file, however, only vdanen can read and write to; no one else can even read this file.
  • The final (temp) is a directory, owned by the user vdanen and group vdanen (a user private group). It is read/write/execute by user vdanen, read/execute by group vdanen, and read/execute by everyone else.

In the context of normal files (and devices), read, write, and execute mean:

  • Read access: The ability to read data from the file. If read access is enabled, a "r" character will be present, if it is denied, a "-" character will be present.
  • Write access: The ability to write data to a file or otherwise modify or delete it. If write access is enabled, a "w" character will be present; if it is denied, a "-" character will be present.
  • Execute access: The ability to execute the file (ie. run the file as a program). If execute access is enabled, a "x" character will be present; if it is denied, a "-" character will be present.

In the context of directories, read, write, and execute mean:

  • Read access: The ability to list the contents of the directory.
  • Write access: The ability to create or delete files in this directory.
  • Execute access: The ability to change into this directory (ie. via cd), and to execute files in this directory.

Changing Permissions

Permissions of files can be changed by the owner of the file (or root). The tool used to modify permissions is chmod. chmod manages permissions in two ways: via symbolic mode or numeric mode.

The fastest way to change permissions is to use numeric mode. This sets absolute permissions to the file through a three-digit number which represents the permissions the file should have. chmod's syntax is as follows:

chmod NNN file [file...]

The first digit represents permissions for the user, the second for the group, and the third for the "others". Each digit is a sum of permissions to be granted. The following values correspond to a certain type of permission:

  • 4 - read permission
  • 2 - write permission
  • 1 - execute permission

Each digit must be a number between 0 and 7. The number 0 indicates no permission, while any number from 1 through 7 indicate some permission the user, group, or world should have to the file, through a sum of the above values.

For example, suppose you wrote a shell script that you wanted others to be able to execute. You might use chmod like this:

$ chmod 711 myscript.sh

This will give the owner of the file read, write, and execute permissions on the file myscript.sh. It will also give members of the owner group and the rest of the world execute only access.

Another example, of a text file, that you wanted to provide owner permissions to read and write, and read-only access to members of the owner group, and no access whatsoever to the rest of the world, you would use:

$ chmod 640 myfile.txt

Using chmod in symbolic form users letters to represent user (u), group (g), other (o), and all (a). You also use characters such as plus (+) to indicate adding permissions, minus (-) to indicate the removal of permissions, or equals (=) to set absolute permissions. Use r to specify read permissions, w for write, and x for execute. You can also use s for suid or sgid, and t for the sticky bit. The following syntax is used by chmod in symbolic form:

chmod [ugoa] [+|-|=] [rwx] file [file...]

For example, to add read permissons to a file of mode 600 (read/write user only), you would use:

$ chmod go+r file.txt

Or to remove read/write permissions from a file that the world has access to (mode 666), you would use:

$ chmod o-rw file.txt

To assign permissions to a file of user and group read/write and world read, you could use:

$ chmod ug=rw,o=r file.txt

of course, you could also use:

$ chmod 664 file.txt

You can also pass options to chmod, such as -R which tells chmod to act recursively (change permissions on all files and subdirectories).

There is actually one more digit in the octal number that defines permissions, and it is the leading digit. The above noted 664 permissions are actually 0664. The leading digit is a special digit that gives special access to a file:

  • 1 - sticky bit
  • 2 - sgid
  • 4 - suid

These bits have special significance. The most widely known of the three is the suid bit, or "set user id on execution". What this does is executes the file as the owner of the file. This is commonly used for applications that need to be run as root, such as /bin/su. Because one must have root privilege to become another user (which is what su does), the su program must actually be executed as root. The only way to do this is to either use [/sudo.php sudo], or to se the suid bit on the program itself. Most systems use the latter.

The sgid bit, or "set group id on execution", does a similar thing, but executes the program as the file's group owner. Instead of changing the UID, like a program with the suid bit set, this changes the GID to the group owner of the file. A program can be both suid and sgid. It is best to avoid using, or creating, suid or sgid files. There is no access restrictions when using such a program, and unless the program is well-written and without flaws, exploitation of such a program could lead to some undesirable consequences. The whole purpose of using suid and sgid bits is to ellevate privilege (or demote it) when executing a file, but there is no real control as to who can execute those programs. It is better to use something like Sudo that can offer a log of who executed what, and give you control over who has the right to access what. This gives you the same functionality of using the suid or sgid bits, without the security risks.

Changing User and Group Ownership

You can also change the ownership of files, by using the chown and chgrp commands. These will change the primary owner and group, respectively, of a file. The syntax for chown is:

chown [-Rcfh] owner[:group] filelist

The -R option changes the ownership recursively, the -c option reports when changes are made, the -f option suppresses most error messages, and the -h option tells chown to operate on a symbolic link itself, and not the file it references. You can also pass --dereference to have chown operate on the file that a symbolic link references, rather than the symbolic link itself. The owner can be the new file owner's name or UID, and you can also change the group by specifying it as well, but it's optional. The user and group must be specified as "user:group" or (in some cases) as "user.group" as well. The filelist is the list of files to modify.

chgrp is handled very similarly, but does not change the ownership of the file. It has the same options as chown. The only difference is you can only specify the group, not both user and group.

Also note that only root can change ownership of a file to another user. A normal, unprivileged user, cannot change the ownership of a file they own to be owned by someone else. This is for your own protection (imagine someone trojaning a file, or writing data they shouldn't be writing to a file, and making the file owned by you... any sysadmin looking at that file would automatically assume you are the culprit). Likewise, chgrp will only allow you to change the group ownership of a file if you are root or a member of the group you are trying to change the ownership to (ie. you have a file owned by joe.joe, but are also a member of the group "users"; you can change the file to be owned by joe.users).

Setting Default Permissions

Setting default permissions essentially means to set the umask on the system. umask is short for "user file-creation mode mask" and is a four digit octal number that is used to determine what permissions will be granted to newly created files. It does this by indicating what permissions are not to be given by default to files and directories that are newly created.

The umask is usually set by the system in /etc/profile or a similar file, but can be modified by users on a per-user basis (ie. a user can set the umask in their ~/.bash_profile file which will override the system default). Because of this, it's a good idea to make the umask somewhat stricter across the board. Also not that the umask is carried on per process; so anything executed before the umask is set will use a really lax default (mode 666 for files and 777 for directories in most Linux, BSD, and UNIX implementations).

Common values for a umask are 022, 027, and 077. This means that files will have a mode of 0644, 0640, and 0600 respectively. Essentially, the umask is derived from the default file creation mode, less the umask, resulting in your desired permissions. A good rule of thumb is to remember that the number 2 in the umask turns off write permissions while the number 7 turns off read, write, and execute permissions. It reads the same way as the other modes previously shown: 022 tells the system to turn off write permissions for group and the world. Obviously, the number 0 means to enable all permissions, thus the default file creation mode (0666) is actually a umask of 022.

As already mentioned, most UNIX systems use a default umask of 022, which is fairly lax. A better umask value would be 077 which makes all files and directories created by users completely unreadable by other users on the system. A user can always change the permissions on the file to grant others the right to read or execute the file. A wise man once said that it is easier to give permissions when someone needs it, than to take permissions away after they've already gotten into it (or something to that effect).

The Sticky Bit

The sticky bit is an interesting, and very useful, means of limiting access to a directory. What it does is indicate to the system that files contained in the directory may only be removed or renamed by the owner of the file (or root). This makes it desirable in "public access" directories such as /tmp. Often, the /tmp directory will be mode 1777, which means any user can read, write, and execute in that directory. By using the sticky bit, we ensure that user joe can't remove user sally's files, and vice versa. This allows us to use a shared directory without fear that someone will remove files we own, which they would normally be allowed to do due to the generous 777 permissions on the directory.

Per-Filesystem Security and Options

Some filesystems provide greater levels of flexibility and control over others. For instance, some provide additional Access Control Lists features that allow you to fine-tune some permissions. Other offer extended attributes to files that prevent anyone, including root, from making changes. Each filesystem is a little bit different, and the changes are worth documenting.

Extending Filesystem Security

There are, obviously, other means of extending filesystem security. The above is merely the basics; they are the "meat and potatoes" of securing permissions and access rights to your system, but other tools are available to bring this even further. With tools like AIDE and Tripwire, you can audit your filesystem; they alert you if files have changed on the system, a great way to know if an intruder has gotten in and changed things on you, like installing a rootkit. Other tools are kernel-level and allow you to provide real security permissions to files via ACLs (Access Control Lists). We will examine as many of these tools as possible.