Linux File permissions

All the Linux users know about the “rwx” file permissions. These defines if the people who is the owner/ in the same group/ any other people can read/write/execute the file.

However, have you notice some other things in the permission field? Sometimes a “s”, sometimes a “t”, or “c”, “b”, “l”… What does this mean? In this article, we’ll check out the meanings of all these characters.

What we are caring about here is the first 10 characters. The first character is “d” if it is a directory, and a “-” if it is a normal file. The following 9 characters can be divided into 3 groups: 2-4, 5-7, 8-10. Which marks the permissions for owner, group, and others, accordingly.

For a file, read, write, and executable is straightforward. For a directory, read and write is easy to understand too. But…. What does “x” for a directory mean? Could we really execute a directory?

What “x” mean for directories

In the Linux file system, everything is a file. The directory is just a special kind of file. And in this “directory” file, there are several blocks, each block holds the information of one file or one sub-directory in it.

Thus we can understand why the r permission is needed to do a ls in a directory: in fact the ls program reads the “directory” file and re-formats it to some human readable text.

And we can understand why we need the w permission to create, delete, or rename a file/sub-directory in a directory: we actually need to write to this “directory” file, to modify the corresponding blocks.

And for x, executable, let’s think it as “search, and read part of the file, and then do things accordingly”.

Now if we want to enter a directory, say cd to it, we’ll need to read part of the “directory” file and do things accordingly. So if we don’t have a x permission on a directory, we can’t cd into it.

And say if we have an executable file in a directory, if we want to run that file, we first need to make sure the file exists (read the “directory” file), and then do things accordingly(executable permission of the “directory” file)

It might be confusing and you might say: “I’ll just make the r and the x appears together”. Right. This is indeed most of the cases. However, with the understanding above, we can do something really cool:

First, let’s setup our experiment environment:

mkdir directory
cd directory
echo “hello” > file

Now if we do:

ls -l

we’ll get something like:

-rw-r–r– 1 ddliu ddliu 6 7 23 15:40 file

The permission bit mights be slightly different, depending on your umask settings, and the user-name/group-name will be different. Now do a:

cd ..
chmod 300 directory
ls -l

And you’ll see:

d-wx—— 2 ddliu ddliu 512 7 23 15:40 directory

We have the executable permission, but not the read permission on this directory. Now if we try to:

cd directory
ls -l

We’ll be able to do the cd command, which is decide by the x permission we have, but the ls -l command will fail:

Opening directory: permission denied

This says we don’t have the r permission, so we can’t read the “directory” file and find out what is in it.

But we know there’s a file named “file” in it. So we can do:

cat file

or:

cd ..
cat directory/file

and we’ll get what we want: the output as:

hello

Note if you are using some “tab completion” on file and directory names of your shell, you’ll find out that they won’t work on the name “file”. This is because the file/directory name completion need to read what is in the directory, and requires the r permission of the “directory” file, which we don’t have here.

The first chatacter

As we said above, Linux treats everything is the file system a file. Most of the time we’ll see directory files (with a d as the first character of the permission field) and normal files (with a – as the first character of the permission field).

However if you do a:

ls /dev

You’ll find many other characters: c, b, and l, etc.

These are for “special” files in Linux. Both c and b marks device files, which corresponds to a device.

In the Linux world, there are two ways to read/write a file: stream based, and block based. Stream based means we’ll need to read or write the file character by character. As for device, this is typically the terminals. And for block based devices, we read/write the file block by block, the block size, 512 bytes, 1024 bytes, will be determined by the device. The most typical device is the disk.

And a l marks a symbolic link file. Think symbolic link file kind of the “file shortcut” on windows. And we’ll talk more about this in a later article.

There are also s and p. Where s means a Unix socket, and p means a named pipeline. These are facilities the Linux programs used to to IPC – Inter Process Communication. Most of the time the programs will create and delete these files automatically, and you don’t need to worry about them.

“s: setuid or setgid

Sometimes we see a s instead of a x in the rwx sequence. This happens to both files and directories, and is called “setuid bit” or “setgid bit”, according to which x it replaced.

A setuid bit or setgid bit on a file means two things:

1. The file is executable
2. The file will be executed with extra privileges

Normally when someone, say Tom, runs a program, he is restricted to his permission, according to his user ID and group ID. This is why he can’t remove another user’s, say Emily’s file:

1. Emily set the permissions so that only she (and the root) can
remove the file

2. The program checks and find out Tom is not Emily, and then refuse
to remove the file

However, if the rm file, which is normally owned by root, has a setuid bit on, it means no matter who runs this program, the system will look it as the root user runs it. Thus in the example above, when the program checks, it find out root can do the remove, and remove the file. This is why you should be very careful when setting the setuid bit on some files.

A setgid bit on a file basically means the same thing. Just the program will run as if it is called by the group who own it, not who called it.

The command we use to add the setuid bit is:

chmod o+s file_name

And you can change the o to g for setgid bit.

We can only set the group ID to a directory. If you try to setgid on a file, it will silently returns, and nothing changed.

The setgid bit on a directory means every file/sub-directory created under that directory, no matter who created it, will have the group owner the same as this directory. Instead of the effective group ID of the creator.

This is useful, when, Tom and Emily belongs two different groups, and now they’ll work on a same project, and want to edit/create the same set of files. In a situation like this, we first make Tom and Emily both in a group, say “projectA”. Note this is not their primary group, so the files they created will still have different group owners.

Now every file they created will have the group owner projectA. And as long as they do a:

chmod g+wr file_name

after they create some files under it, the files will be readable and writable to both of them, no matter who created it. This is especially useful, when, there are several dozens or hundreds people in this project.

“t”: the sticky bit

The t, sticky bit, can be set on binary executable files and directories. The command we uses to set a sticky bit is:

chmod +t file_name

Note we don’t need to specify to whom this bit is set. The t will always appear as the last character.

When a sticky bit is set on a binary executable file, that file will be “stick-ed” in the memory, which means it will always be hold in the physical memory, and never be switched out to SWAP. This will improve the performance of this program, but may slow down the other programs, cause those programs will need to be switched out more frequently, if you don’t have enough memory.

If a directory have the sticky bit on, it means all the files/sub-directories under it will only be deleted or modified by the owner or someone who have the write permission on the file/sub-directory, not who have write permission of the directory having the sticky bit.

On most systems the /tmp directory has this bit on:

% ls -ld /tmp
drwxrwxrwt 11 root wheel 1024 7 23 17:21 /tmp/

This perfectly fit the need of a global temporary directory: every one can create files under it (the w permission), but only the owner or someone have write permission on the file can delete or modify it.