5. The UNIX Filesystem
Contents:
The UNIX filesystem controls the way that information in files and directories is stored on disk and other forms of secondary storage. It controls which users can access what items and how. The filesystem is therefore one of the most basic tools for enforcing UNIX security on your system. Information stored in the UNIX filesystem is arranged as a tree structure of directories and files. The tree is constructed from directories and subdirectories within a single directory, which is called the root . [1] Each directory, in turn, can contain other directories or entries such as files, pointers (symbolic links) to other parts of the filesystem, logical names that represent devices (such as /dev/tty ), and many other types.[2]
This chapter explains, from the user's point of view, how the filesystem represents and protects information. 5.1 FilesFrom the simplest perspective, everything visible to the user in a UNIX system can be represented as a "file" in the filesystem - including processes and network connections. Almost all of these items are represented as "files" each having at least one name, an owner, access rights, and other attributes. This information is actually stored in the filesystem in an inode (index node), the basic filesystem entry. An inode stores everything about a filesystem entry except its name; the names are stored in directories and are associated with pointers to inodes. 5.1.1 DirectoriesOne special kind of entry in the filesystem is the directory . A directory is nothing more than a simple list of names and inode numbers. A name can consist of any string of any characters with the exception of a "/" character and the "null" character (usually a zero byte).[3] There is a limit to the length of these strings, but it is usually quite long: 1024 or longer on many modern versions of UNIX ; older AT&T versions limit names to 14 characters or less.
These strings are the names of files, directories, and the other objects stored in the filesystem. Each name can contain control characters, line feeds, and other characters. This can have some interesting implications for security, and we'll discuss those later in this and other chapters. Associated with each name is a numeric pointer that is actually an index on disk for an inode. An inode contains information about an individual entry in the filesystem; these contents are described in the next section. Nothing else is contained in the directory other than names and inode numbers. No protection information is stored there, nor owner names, nor data. The directory is a very simple relational database that maps names to inode numbers. No restriction on how many names can point to the same inode exists, either. A directory may have 2, 5, or 50 names that each have the same inode number. In like manner, several directories may have names that associate to the same inode. These are known as links [4] to the file. There is no way of telling which link was the first created, nor is there any reason to know: all the names are equal in what they access. This is often a confusing idea for beginning users as they try to understand the "real name" for a file.
This also means that you don't actually delete a file with commands such as rm. Instead, you unlink the name - you sever the connection between the filename in a directory and the inode number. If another link still exists, the file will continue to exist on disk. After the last link is removed, and the file is closed, the kernel will reclaim the storage because there is no longer a method for a user to access it. Every normal directory has two names always present. One entry is for " . " (dot), and this is associated with the inode for the directory itself; it is self-referential. The second entry is for " .. " (dot-dot), which points to the "parent" of this directory - the directory next closest to the root in the tree-structured filesystem. The exception is the root directory itself, named "/". In the root directory, ".." is also a link to "/". 5.1.2 InodesFor each object in the filesystem, UNIX stores administrative information in a structure known as an inode. Inodes reside on disk and do not have names. Instead, they have indices (numbers) indicating their positions in the array of inodes. Each inode generally contains:
The last three pieces of information, stored for each item, and coupled with UID/GID information about executing processes, are the fundamental data that UNIX uses for practically all operating system security. Other information can also be stored in the inode, depending on the particular version of UNIX involved. Some systems may also have other nodes such as vnodes, cnodes, and so on. These are simply extensions to the inode concept to support foreign files, RAID [5] disks, or other special kinds of filesystems. We'll confine our discussion to inodes, as that abstraction contains most of the information we need.
Figure 5.1 shows how information is stored in an inode. Figure 5.1: Files and inodes5.1.3 Current Directory and PathsEvery item in the filesystem with a name can be specified with a pathname . The word pathname is appropriate because a pathname represents the path to the entry from the root of the filesystem. By following this path, the system can find the inode of the referenced entry. Pathnames can be absolute or relative. Absolute pathnames always start at the root, and thus always begin with a "/", representing the root directory. Thus, a pathname such as /homes/mortimer/bin/crashme represents a pathname to an item starting at the root directory. A relative pathname always starts interpretation from the current directory of the process referencing the item. This concept implies that every process has associated with it a current directory . Each process inherits its current directory from a parent process after a fork (see Appendix C, UNIX Processes ). The current directory is initialized at login from the sixth field of the user record in the /etc/passwd file: the home directory . The current directory is then updated every time the process performs a change-directory operation (chdir or cd). Relative pathnames also imply that the current directory is at the front of the given pathname. Thus, after executing the command cd /usr, the relative pathname lib/makekey would actually be referencing the pathname /usr/lib/makekey . Note that any pathname that doesn't start with a "/" must be relative. 5.1.4 Using the ls CommandYou can use the ls command to list all of the files in a directory. For instance, to list all the files in your current directory, type: % ls -a instructions letter notes invoice more-stuff stats % You can get a more detailed listing by using the ls -lF command: % ls -lF total 161 -rw-r--r-- 1 sian user 505 Feb 9 13:19 instructions -rw-r--r-- 1 sian user 3159 Feb 9 13:14 invoice -rw-r--r-- 1 sian user 6318 Feb 9 13:14 letter -rw------- 1 sian user 15897 Feb 9 13:20 more-stuff -rw-r----- 1 sian biochem 4320 Feb 9 13:20 notes -rwxr-xr-x 1 sian user 122880 Feb 9 13:26 stats* % The first line of output generated by the ls command ("total 161" in the example above) indicates the number of kilobytes taken up by the files in the directory.[6] Each of the other lines of output contains the fields, from left to right, as described in Table 5.1 .
The ls -F option makes it easier for you to understand the listing by printing a special character after the filename to indicate what it is, as shown in Table 5.2 .
Thus, in the directory shown earlier, the file stats is an executable program file; the rest of the files are regular text files. The -g option to the ls command alters the output, depending on the version of UNIX being used. If you are using the Berkeley-derived version of ls,[8] you must use the ls -g option to display the file's group in addition to the file's owner:
% ls -lFg total 161 -rw-r--r-- 1 sian user 505 Feb 9 13:19 instructions -rw-r--r-- 1 sian user 3159 Feb 9 13:14 invoice -rw-r--r-- 1 sian user 6318 Feb 9 13:14 letter -rw------- 1 sian user 15897 Feb 9 13:20 more-stuff -rw-r----- 1 sian biochem 4320 Feb 9 13:20 notes -rwxr-xr-x 1 sian user 122880 Feb 9 13:26 stats* % If you are using an AT&T -derived version of ls,[9] using the -g option causes the ls command to only display the file's group:
% ls -lFg total 161 -rw-r--r-- 1 user 505 Feb 9 13:19 instructions -rw-r--r-- 1 user 3159 Feb 9 13:14 invoice -rw-r--r-- 1 user 6318 Feb 9 13:14 letter -rw------- 1 user 15897 Feb 9 13:20 more-stuff -rw-r----- 1 biochem 4320 Feb 9 13:20 notes -rwxr-xr-x 1 user 122880 Feb 9 13:26 stats* % 5.1.5 File TimesThe times shown with the ls -l command are the modification times of the files ( mtime). You can obtain the time of last access (the atime) by providing the -u option (for example, by typing ls -lu ). Both of these time values can be changed with a call to a system library routine.[10] Therefore, as the system administrator, you should be in the habit of checking the inode change time ( ctime) by providing the -c option; for example, ls -lc . You can't reset the ctime of a file under normal circumstances. It is updated by the operating system whenever any change is made to the inode for the file.
Because the inode changes when the file is modified, ctime reflects the time of last writing, protection change, or change of owner. An attacker may change the mtime or atime of a file, but the ctime will usually be correct. Note that we said "usually." A clever attacker who gains superuser status can change the system clock and then touch the inode to force a misleading ctime on a file. Furthermore, an attacker can change the ctime by writing to the raw disk device and bypassing the operating system checks altogether. And if you are using Linux with the ext2 filesystem, an attacker can modify the inode contents directly using the debugfs command. For this reason, if the superuser account on your system has been compromised, you should not assume that any of the three times stored with any file or directory are correct.
5.1.6 Understanding File PermissionsThe file permissions on each line of the ls listing tell you what the file is and what kind of file access (that is, ability to read, write, or execute) is granted to various users on your system. Here are two examples of file permissions: -rw------- drwxr-xr-x The first character of the file's mode field indicates the type of file described in Table 5.3 .
The next nine characters taken in groups of three indicate who on your computer can do what with the file. There are three kinds of permissions:
Similarly, there are three classes of permissions:
In the ls -l command, privileges are illustrated graphically (see Figure 5.2 ). Figure 5.2: Basic permissions5.1.7 File Permissions in DetailThe terms read , write , and execute have very specific meanings for files, as shown in Table 5.4 .
File permissions apply to devices, named sockets, and FIFOS exactly as they do for regular files. If you have write access, you can write information to the file or other object; if you have read access, you can read from it; and if you don't have either access, you're out of luck. File permissions do not apply to symbolic links. Whether or not you can read the file pointed to by a symbolic link depends on the file's permissions, not the link's. In fact, symbolic links are almost always created with a file permission of "rwxrwxrwx" (or mode 0777, as explained later in this chapter) and are ignored by the operating system.[11]
Note the following facts about file permissions:
Most people think that file permissions are pretty basic stuff. Nevertheless, many UNIX systems have had security breaches because their file permissions are not properly set.
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|