15.4.2 Permissions On Directories: /bin/ls
15.4.2 Permissions On Directories: /bin/ls
15.4.2 Permissions On Directories: /bin/ls
2 Permissions on Directories
Directories have the same permission scheme as files. However, the three permis-
sions are interpreted differently:
� Read: The contents (i.e., the list of filenames) of the directory may be listed
(e.g., by ls).
If experimenting to verify the operation of the directory read permission bit,
be aware that some Linux distributions alias the ls command to include flags
(e.g., F) that require access to i-node information for files in the directory,
and this requires execute permission on the directory. To ensure that we are
using an unadulterated ls, we can specify the full pathname of the command
(/bin/ls).
� Write: Files may be created in and removed from the directory. Note that it is
not necessary to have any permission on a file itself in order to be able to
delete it.
� Execute: Files within the directory may be accessed. Execute permission on a
directory is sometimes called search permission.
When accessing a file, execute permission is required on all of the directories listed
in the pathname. For example, reading the file /home/mtk/x would require execute
permission on /, /home, and /home/mtk (as well as read permission on the file x itself).
If the current working directory is /home/mtk/sub1 and we access the relative path-
name ../sub2/x, then we need execute permission on /home/mtk and /home/mtk/sub2
(but not on / or /home).
Read permission on a directory only lets us view the list of filenames in the
directory. We must have execute permission on the directory in order to access the
contents or the i-node information of files in the directory.
Conversely, if we have execute permission on a directory, but not read permission,
then we can access a file in the directory if we know its name, but we cant list the
contents of (i.e., the other filenames in) the directory. This is a simple and fre-
quently used technique to control access to the contents of a public directory.
To add or remove files in a directory, we need both execute and write permis-
sions on the directory.
F i l e A tt r i b u t es 297
The rules applied by the kernel when checking permissions are as follows:
The checks against owner, group, and other permissions are done in order, and
checking stops as soon as the applicable rule is found. This can have an unexpected
consequence: if, for example, the permissions for group exceed those of owner,
then the owner will actually have fewer permissions on the file than members of
the files group, as illustrated by the following example:
$ echo 'Hello world' > a.txt
$ ls -l a.txt
-rw-r--r-- 1 mtk users 12 Jun 18 12:26 a.txt
$ chmod u-rw a.txt Remove read and write permission from owner
$ ls -l a.txt
----r--r-- 1 mtk users 12 Jun 18 12:26 a.txt
$ cat a.txt
cat: a.txt: Permission denied Owner can no longer read file
$ su avr Become someone else
Password:
$ groups who is in the group owning the file
users staff teach cs
$ cat a.txt and thus can read the file
Hello world
Similar remarks apply if other grants more permissions than owner or group.
Since file permissions and ownership information are maintained within a file
i-node, all filenames (links) that refer to the same i-node share this information.
Linux 2.6 provides access control lists (ACLs), which make it possible to define
file permissions on a per-user and per-group basis. If a file has an ACL, then a mod-
ified version of the above algorithm is used. We describe ACLs in Chapter 17.
#include <unistd.h>
Constant Description
F_OK Does the file exist?
R_OK Can the file be read?
W_OK Can the file be written?
X_OK Can the file be executed?
The time gap between a call to access() and a subsequent operation on a file means
that there is no guarantee that the information returned by access() will still be true
at the time of the later operation (no matter how brief the interval). This situation
could lead to security holes in some application designs.
Suppose, for example, that we have a set-user-ID-root program that uses access()
to check that a file is accessible to the real user ID of the program, and, if so, per-
forms an operation on the file (e.g., open() or exec()).
F i l e A tt r i b u t es 299
The problem is that if the pathname given to access() is a symbolic link, and a
malicious user manages to change the link so that it refers to a different file before
the second step, then the set-user-ID-root may end up operating on a file for which the
real user ID does not have permission. (This is an example of the type of time-of-
check, time-of-use race condition described in Section 38.6.) For this reason, recom-
mended practice is to avoid the use of access() altogether (see, for example,
[Borisov, 2005]). In the example just given, we can achieve this by temporarily
changing the effective (or file system) user ID of the set-user-ID process, attempting
the desired operation (e.g., open() or exec()), and then checking the return value and
errno to determine whether the operation failed because of a permissions problem.
The GNU C library provides an analogous, nonstandard function, euidaccess()
(or synonymously, eaccess()), that checks file access permissions using the effec-
tive user ID of the process.