Linux is a multi-user system, so every file records who owns it and who may read, change or run it. "Permission denied" is one of the most common errors you'll hit on a server. This note shows how to read permissions, change them, and get root access only when you need it.
Reading a permission string#
Before you can fix a permission problem, you need to see the current permissions. Run ls -l and each line starts with ten characters.
$ ls -l deploy.sh
-rwxr-xr-- 1 alice devs 812 Oct 18 09:30 deploy.sh
The first character is the file type: - for a regular file, d for a directory, l for a symbolic link. The next nine are three sets of rwx, one for each class of user.
| Characters | Class | In the example |
|---|---|---|
| 2 to 4 | Owner (user) | rwx: alice can read, write and run it |
| 5 to 7 | Group | r-x: members of devs can read and run it |
| 8 to 10 | Others | r--: everyone else can only read it |
A - in a slot means that permission is off. The owner (alice) and group (devs) come after the link count.
What r, w and x mean#
On a file, r, w and x mean what you'd expect. On a directory, the same letter means something different.
| On a file | On a directory | |
|---|---|---|
r (read) |
Read the contents | List the names inside |
w (write) |
Change the contents | Create, delete or rename entries inside |
x (execute) |
Run it as a program | Enter it (cd) and reach files inside |
Two results follow from this. You can delete a file you can't write, if you can write its directory. And a directory without x blocks access to everything inside, even files with open permissions.
chmod: change permissions#
Once you can read permissions, you'll want to change them. Only the file's owner and root can do that. chmod takes either symbolic or octal modes.
Symbolic mode#
Symbolic mode names who, what change, and which permission.
| Part | Options |
|---|---|
| Who | u owner, g group, o others, a all |
| Change | + add, - remove, = set exactly |
| Permission | r, w, x |
chmod u+x deploy.sh # owner may run it
chmod go-w config.yml # group and others lose write
chmod a=r notes.txt # everyone: read only
chmod -R g+rw shared/ # recursive
Octal mode#
The other way to write the same change is octal, which you'll see a lot in docs and scripts. Octal mode sets all nine bits at once. Each permission has a value, and you add them per class: r = 4, w = 2, x = 1.
| Digit | Bits | Meaning |
|---|---|---|
| 7 | rwx |
4 + 2 + 1 |
| 6 | rw- |
4 + 2 |
| 5 | r-x |
4 + 1 |
| 4 | r-- |
4 |
| 0 | --- |
none |
chmod 755 deploy.sh # rwxr-xr-x: scripts, binaries, directories
chmod 644 index.html # rw-r--r--: ordinary files
chmod 600 ~/.ssh/id_ed25519 # rw-------: private keys
chmod on a symbolic link changes the target file. The link's own permissions aren't used.
chown: change owner and group#
Sometimes the permissions are right but the file belongs to the wrong user or group. chown sets a file's owner, group, or both. Changing the owner needs root. An owner may change the group to another group they belong to.
sudo chown alice:devs report.txt # owner and group
sudo chown alice report.txt # owner only
sudo chown :devs report.txt # group only (chgrp does this too)
sudo chown -R www-data:www-data /srv/www
Special bits#
Beyond the nine rwx bits, three extra bits change how execution and deletion work. They show up in the x slots of the string.
| Bit | Octal | Shows as | Effect |
|---|---|---|---|
| SetUID | 4000 | s in owner's x |
A program runs with the owner's rights, not the caller's |
| SetGID | 2000 | s in group's x |
Runs with the group's rights. On a directory, new files inherit its group. |
| Sticky | 1000 | t in others' x |
In a directory, only a file's owner (or root) can delete or rename it |
A capital S or T means the special bit is set but the matching x bit isn't.
Examples#
You'll find two of these bits on every Linux system:
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root ... /usr/bin/passwd
$ ls -ld /tmp
drwxrwxrwt 10 root root ... /tmp
passwdhas SetUID and is owned by root. Any user can run it, and it runs as root, so it can update the password database./tmphas the sticky bit. Everyone can write there, but you can't delete another user's files. Without thet, any user could delete anyone's files in/tmp.
Set them with chmod u+s, chmod g+s, chmod +t, or a fourth leading octal digit, such as chmod 1777 /shared or chmod 2775 /team.
A SetUID root program is a classic attack target. A bug in it gives an attacker root. Don't add SetUID to your own scripts.
Extra markers after the string#
Back to the ls -l string from the start: sometimes it has an eleventh character.
| Marker | Meaning |
|---|---|
+ |
The file has an ACL (access control list) with extra per-user or per-group rules |
. |
The file has a security context, such as SELinux (Linux) |
@ |
The file has extended attributes (macOS ls only) |
ACLs grant rights beyond the owner, group and others model. Read them with getfacl and change them with setfacl.
setfacl -m u:bob:rw report.txt # give bob read and write
getfacl report.txt
su vs sudo#
Several commands above, like chown, needed root. You need root for system changes, such as installing packages or editing /etc, and there are two ways to get it.
su |
sudo |
|
|---|---|---|
| What it does | Starts a shell as another user (root by default) | Runs one command as another user (root by default) |
| Password asked | The target user's password | Your own password |
| Scope | A whole shell until you exit |
One command |
| Audit | Hard to tell who did what | Each command is logged with your name |
su -l alice # full login shell as alice
sudo apt-get update # one command as root
sudo -u postgres psql # one command as another user
sudo -i # root login shell, when you must
su -l (or su -) loads the target user's environment and moves to their home directory. Plain su keeps much of your current environment. sudo is the modern default, because no one needs to share the root password and every command has an owner.
The sudoers file#
/etc/sudoers decides who may run what with sudo. Always edit it with visudo. It checks the syntax before saving, so a typo can't lock everyone out of sudo. Each rule line has the shape shown in the comment:
# user hosts=(run as) commands
alice ALL=(ALL:ALL) ALL
%devs ALL=(root) /usr/bin/systemctl restart myapp
The first line gives alice full root access. The second lets members of the devs group restart one service and nothing else. Many distros put extra rules in files under /etc/sudoers.d/.
Key takeaways#
ls -lshows type, thenrwxfor owner, group and others.- On a directory,
wlets you create and delete entries andxlets you enter it. - Octal:
r= 4,w= 2,x= 1. Use 755 for scripts and directories, 644 for files, 600 for secrets. - SetUID runs a program as its owner; SetGID shares a group; the sticky bit protects files in shared directories like
/tmp. - A trailing
+means an ACL. Usegetfaclandsetfacl. - Prefer
sudooversu, and edit sudoers only withvisudo.