File permissions are one of the most fundamental security mechanisms of any computer system. Understanding how they are managed and interacted with is an essential skill for any linux operator and a robust permission setup can drastically improve a system's security and stability. Linux brings it#s own flavour of file and directory permissions, with a simple yet powerful mechanism to control access.
File permissions
Access to files in linux is managed using a set of three basic permissions:
r
: Allows reading file contentsw
: Allows writing to (and deleting) the filex
: Allows executing the file as a program
Separate permissions can be defined for three entities: the user owning the file (u), the group owning the file (g), and others (o). You can view the permissions of any file or directory using ls -l
:
The output will list all directory contents, one per line. Each line starts with a d
(directory) or -
(file). The next 9 characters are the permissions for the user, group and others, respectively.
Directory permissions
Permissions on directories follow a similar approach by reusing the rwx permissions, but their meaning is slightly altered:
r
: Allows listing directory contents withls
, but cannot access them orcd
into the directoryw
: Allows writing file contents (create, rename, delete), but does not work withoutx
x
: Allows changing into directory (cd
) and accessing files inside, but cannot list directory contents (ls
)
To illustrate this further, let's assume we have a test directory test/
with a single file sample.txt
inside. The sample.txt
file has full rwx
permissions for the current user, so all access controls originate from the test/
directory:
mkdir test/
echo "contents of sample.txt" > test/sample.txt
chmod a+rwx test/sample.txt
chmod a-rwx test
Setting only read (r) permissions on the directory allows reading the names of contents:
chmod u=r test
ls -l test
But the output contains an error when trying to read metadata from the file inside:
ls: cannot access 'test/sample.txt': Permission denied
total 0
-????????? ? ? ? ? ? sample.txt
Trying to cd
into the directory or read the contents of sample.txt
throws errors:
cat test/sample.txt
Output:
cat: test/sample.txt: Permission denied
Changing the permissions to execute (x) only, the inverse happens:
chmod u=x test
ls -l test
Listing the directory contents is not allowed anymore:
ls: cannot open directory 'test/': Permission denied
But if you know the name of the file inside, you can access it directly:
cat test/sample.txt
This correctly prints the file contents:
contents of sample.txt
A last thing to note is that the write (w) permission implicitly requires the execute (x) permission as well, as you technically need to enter the directory in order to create files in it.
Special permissions
In addition to the traditional rwx permissions, there are some special permissions that change the behaviour of interactions:
SUID
: Makes a file execute with the permissions of the file owner no matter who runs it. Often used to run programs that need superuser privileges without giving superuser access to users directly.
SGID
: Makes a file execute with the permissions of the file group no matter who runs it. On directories, makes files created inside inherit the directory group.
Sticky bit
: For directories, lets only the owner of files or directories delete or rename them. This mode is frequently used for shared directories like/tmp
.
Special permissions are bound to their respective entity: SUID to the user (u
), SGID to the group (g
) and the sticky bit to others (o
). When using ls -l
, they will show up in the position of the x
permission in their respective entity as s
for SUID/SGID or t
for the sticky bit:
Since you cannot see if the x
permission is set in the space occupied by special permissions, you need to use different commands like getfacl
to check exact permissions for these files.
Changing ownership
Modifying ownership of files and directories is done with the chown
(change owner) command:
chown tom:users file.txt
This example changes the user for file.txt
to tom
and it's group to users
. You can modify both user and group ownership at once, or one at a time.
To change only the user, omit the group portion:
chown tom file.txt
Changing only the group requires the leading colon :
in front of the group name to work:
chown :users file.txt
Note that changing to user of a file requires superuser privileges, but you may change it's group to any group your current user has access to. Superusers can change ownership information without restrictions.
Changing permissions
To modify the permissions of a file or directory, the chmod
command is used. It works by specifying the entities you want to change (u
= user, g
= group, o
= others), the way you want to change them (-
to remove permissions, +
to add permissions, =
to set exact permissions) and the permissions themselves (r
= read, w
= write, x
= execute).
For example, to add read permissions for others to a file test.txt
:
chmod o+r test.txt
Or to set the permissions for user and group to read and execute:
chmod ug=rx test.txt
Changing the permissions for everyone at once can be done through either ugo, it's alias a or by omitting the entity altogether:
chmod ugo+r test.txt
chmod a+r test.txt
chmod +r test.txt
The above commands all have the same effect.
Special permissions are set the same way, with s
for SUID or SGID, and t
for sticky bit:
chmod +t test/
Since special permissions are bound to a specific entity, setting them on different ones does nothing (e.g. u+t
has no effect since sticky bit belongs to o
). Because of this, entities are typically omitted for special permissions (using just +t
). Be careful when omitting entities, since using +s
without u
or g
will apply both SUID and SGID at the same time.
The owner of a file can take away their own access to a file, but not their ability to modify it's permissions. Even if they have removed all rwx
permissions for themselves, they can still use chmod
to give themselves these permissions back. The permissions otherwise function normally for them (e.g. trying to read a file without r
permissions still results in Permission Denied
errors, even if the user owns it).
Octal filemode notation
You may have heard of octal filemodes before, or seen chmod
used with numbers like 755. The numbering system is an alternative way to specify exact permissions for a file or directory in linux. It's name octal refers to the base-8 numbering system, as there are 8 possible combinations of rwx permissions (none, r, w, x, rw, rx, wx, rwx).
The octal system works by assigning each permission a number:
4
: read (r)2
: write (w)1
: execute (x)0
: no permissions
To represent a filemode, the corresponding numbers are added. As an example, to refer to rw permissions, one would add the 4
from read and 2
from write permissions and arrive at 6
.
An octal filemode can be applied directly using chmod
as a 3 digit number, each digit representing the permissions for user, group and others, respectively. To grant only the owner rw access to a file, you can use the the octal filemode 600
:
chmod 600 test.txt
The permissions on the test.txt
file are now equal to rw-------
: rw (6
) for user, none for group (0
) and none for others (0
).
Special permissions can also be expressed in octal form, as an optional prefix digit using the same addition:
4
: SUID2
: SGID1
: Sticky bit0
(or only 3 digits): no special permissions
In octal mode, these permissions don't interfere with their entity, and are added as an extra digit in front of the filemode instead:
chmod 5777 test.txt
This grants full rwx permissions for everyone (777
), as well as setting the SUID and Sticky bit (5
= 4
for SUID + 1
for Sticky bit). When the digit for the special permissions is missing from a filemode, it is assumed to be 0
(e.g. 755
does not set any special permissions).