Background
Prerequisite: Basic knowledge about file systems (ECS 150)
Modern file systems are actually just files that have entries to other files. Directories in Linux is no exception. With these knowledge in mind, we can understand the somewhat unintuitive directory permissions. This article aims to not only explain but also decipher the reasoning behind the read, write, and execute (actually search) permissions on Linux directories.
Files
At a high level, a file consists of a directory entry, an inode, and an associated data region section.
The inode of a file contains metadata about the file such as where and how big
the file is in the data region. On the other hand, the data region holds the
actual content of the file. Notably, access control information is also held in
the inode, such as stuff like owner and permission bits. The permission
bits are what determine what someone can do to a file. (man 7 inode
)
I'll assume that the reader knows a little about file
permissions
already, so here is a quick review: The permission bits come in three types:
read, write, and execute. These determine how a subject can interact with
the file's data region -- read, write, or execute the content of the file.
(man 7 inode
)
Directories
A directory is a file with two notable traits:
- The functionality of its
execute
permission bit is slightly different than normal files, which we will cover in the next section. - The data region of the directory contains what is essentially a map from names to inodes.
Directory permissions
With that, let's jump into the permissions bits of a directory! We'll start by
creating a directory without any permissions for the user eric
.
1 | # `sudo` makes the owner of the directory `root` |
Read
As mentioned above, the read permission bit allows the reading of the data
region of a file. The data region of a directory is just the name-inode pairs,
something read by ls
. So, we expect ls
to work if we have read permission
for super
.
1 | $ ls super |
ls
did output the names of the file inside super
. However, why can't I
read super/public.txt
? Because read permission only allows one to
read names and which inode is associated with each name; it does not grant
permission to read the contents of the inode; for that, we need a different,
new-ish permission.
Search or execute
This is the interesting part of directory permissions. The execute permission is pretty intuitive on normal files, but it doesn't make much sense on directories, which is why Linux decided to use the bit for a different permission: search.
The search permission allows one to "access" files in the directory.
Essentially, it allows one to not only read the name of the files but also their
inodes. As such, reading super/public.txt
without search, such as in the
case of cat super/public.txt
, fails because one can't read a file without
accessing metadata in the inode like data region address. (man 2 chmod
)
ls -la
without search
We can further illustrate this with ls -l
. This command lists some of the
file's metadata such as its permission bits and owners. Without the search
permission, we get this.
1 | $ ls -l super |
We can see that ls
is trying to access the file for its metadata and got
denied. We can only see the name of the file, provided by read on the
directory.
cd
and some speculation
An important access controlled by search is the ability to change the current
working directory (cwd) to the directory in question via the cd
command (or more
fundamentally, the chdir()
system call).
chdir()
returns access error when any of the directories on its path ---
including the last directory --- is missing search. A corollary is that you
cannot cd
into a directory without search (man 2 chdir
)
My speculation on the reasoning behind this design is that the cwd's goal is to make path resolution easier for the user, and because any path from a cwd without search will be rejected, a cwd without search is pointless.
Path resolution is the act of resolving a pathname to a file. The aspect of path
resolution relevant to us is the access control: if any non-final component of
the path doesn't have search, then an EACCESS
error is returned. This makes
sense: a non-final directory not having search means that its child component's
inode cannot be accessed, rendering the path invalid.(man 7 path_resolution
)
One of the two types of path resolution, relative path resolution, begins at the cwd. As such, any relative path will have its cwd as a non-final component. Given this, if the cwd does not have search, then any relative path will be invalid. As such, it makes sense to not allow cwd to be without search.
Interesting cases
Since write is similar to read, instead of going through the write permission in exhaustive detail, I'll go through some interesting case studies.
Only search
Only having search permission is unexpectedly powerful. Here's some stuff you can do:
1 | ~$ cd super |
Only write
On the other end of the spectrum, only having write permissions doesn't let me really do anything. write allows me to modify the data region of the directory, essentially adding, renaming, or deleting entries in the directory. However, all of these things also require modifications to some file metadata such as the last-changed time.
1 | $ touch super/test.txt |
Conclusion
With this article, I hope that Linux directory permissions that seemed arbitrary now makes more sense (especially search). I encourage you to experiment yourself to get a better understanding than reading. Hope you have a nice day!