Skip to content
New

DeepSeek V4.1 Flash free for 7 days: 10M tokens a day after any top-up. Until Nov 30.

How it works

Linux Permissions: Users, Groups, chmod and umask

Linux owners, groups, rwx bits, chmod, umask and setuid, with a lab that tests access as a second user and finds risky file modes.

Beginner13 min readBy NotHoly

Linux permissions decide who can read, change and run each file on the system. Most problems you meet in a security review are not exotic exploits. They are a config file that any local account can write, a script that a root service runs but a normal user can edit, or a binary with the setuid bit set that nobody remembers adding. This article builds the mechanism from the bottom up: owners, groups, the rwx bits, chmod, umask, and the special bits that matter most in a review. You will create files, change their modes, test access as a second local user in a lab VM, and search for risky permissions.

The core idea is least privilege. A process should have only the access it needs, and a file should be writable only by the people and programs that are supposed to change it. File modes are the first place Linux enforces that rule, so they are the first thing to check.

What a file permission is

Every file and directory carries three things that decide access:

  1. An owner, one user account.
  2. A group, one group account.
  3. A mode, a set of bits that says what the owner, the group and everyone else may do.

Run this on any file in your home directory:

bash
ls -l notes.txt

The first character is the file type (- is a regular file, d is a directory, l is a symbolic link). The next nine characters are the mode. The owner and group names come after the link count.

The kernel checks permissions every time a process opens a file. A shell, a web server and a cron job all go through the same check. If the check fails, you get Permission denied. The file system does not care whether the process is trusted.

Owners, groups and everyone else

The mode has three triplets, one for each class of user:

  • User (u): the account that owns the file.
  • Group (g): the members of the group that owns the file.
  • Other (o): every account that is neither the owner nor a member of the group.

Linux checks the classes in order. If your account is the owner, the owner bits apply and the group and other bits are ignored, even when those would grant more. This surprises people. A file whose owner bits are --- will not open for its owner, even if the group bits are rwx and the owner belongs to that group.

Group membership is a separate list. Check yours with:

bash
id
groups

A change to group membership usually takes effect at the next login, not in the shell where you ran the command.

Reading the rwx bits

Each triplet holds three bits:

Bit On a regular file On a directory
r (read, value 4) Read the contents List the names inside
w (write, value 2) Change the contents Create, rename or delete entries
x (execute, value 1) Run it as a program Enter the directory and reach its entries

Two points trip up beginners.

First, a directory's x bit is what lets you pass through it. A directory with r but no x lets you see names but not open them. A directory with x but no r lets you open a file whose exact name you already know, but not list the directory.

Second, write permission on a file does not let you delete it. Deleting depends on write and execute permission on the directory that holds the entry. A file you own inside a directory you cannot write to still cannot be removed by you.

Symbolic and octal notation

chmod accepts two notations for the same thing.

Octal. Each triplet becomes one digit, the sum of its bits: r is 4, w is 2, x is 1. So rw- is 6, r-- is 4, r-x is 5 and rwx is 7. The mode 644 means owner read and write (6), group read (4), other read (4). The mode 600 means only the owner can read or write.

Symbolic. You name the class, the operator and the bits:

  • Classes: u (owner), g (group), o (other), a (all). With no class given, a is assumed, except that umask bits are left alone.
  • Operators: + adds bits, - removes them, = sets exactly those bits in the class and clears the rest.

So chmod u=rw,go=r notes.txt gives the same result as chmod 644 notes.txt. chmod g+w notes.txt adds group write and leaves the other bits as they are.

Octal is compact and easy to paste into scripts. Symbolic is safer for a single change, because it does not wipe bits you did not think about. Expect both in a review, in config management files, Dockerfiles and install scripts.

chmod step by step

chmod changes the mode. On a file, only its owner or root can run it successfully. Anyone else gets Operation not permitted.

A safe habit is to read the mode, change it, and read it again:

bash
stat -c '%a %A %U:%G %n' notes.txt
chmod 600 notes.txt
stat -c '%a %A %U:%G %n' notes.txt

stat -c prints the octal mode (%a), the symbolic mode (%A), the owner and group names (%U, %G) and the file name (%n). You will use this format throughout the lab.

chown changes the owner and chgrp changes the group. Changing ownership to another user normally needs root. Do not run chown -R on a tree until you have listed what it will touch.

umask: default modes for new files

When a program creates a file, it asks for a starting mode. For a regular file the starting value is 666. For a directory it is 777. The umask removes bits from that starting value. The shell sets it, and every file and directory the shell and its children create goes through it.

Most Linux distributions default to 022. For a file, 666 minus 022 is 644, so new files are rw-r--r--. For a directory, 777 minus 022 is 755, so new directories are rwxr-xr-x. The umask only removes permissions. A mode can never end up more permissive than the starting value.

Check your value:

bash
umask

A stricter umask such as 077 gives 600 files and 700 directories, which only the owner can access. A looser one such as 002 gives 664 files and 775 directories, which the group can write. A umask set in a shell profile affects that shell and its children. It does not change files that already exist.

setuid, setgid and the sticky bit

Four-digit octal modes add a leading digit for three special bits:

  • setuid (4000): when an executable runs, it runs with the file owner's user ID instead of the caller's. A root-owned binary with setuid runs as root.
  • setgid (2000): on an executable, it runs with the file's group ID. On a directory, new entries inherit the directory's group.
  • sticky (1000): on a directory, only an entry's owner or root can rename or delete it, even if everyone can write to the directory. /tmp is the classic example.

ls -l shows setuid as s in the owner's execute position, and sticky as t in the other execute position. On Ubuntu 24.04 the line for passwd looks like this:

text
-rwsr-xr-x 1 root root 64152 May 30  2024 /usr/bin/passwd

Programs like passwd need setuid because they must write protected account files on behalf of a normal user. The risk is that every setuid root binary lets a normal user run code with root rights. A bug in one, such as a memory corruption or an unsafe call to a helper program, can become a local privilege escalation. Reviewers keep a short list of setuid binaries and compare it with a known baseline. A new setuid file that nobody installed on purpose is a finding that needs an answer.

World-writable files are the other common problem. A file with o+w lets any local account change its contents. If that file is a script, a config read by a root service, or a binary in a directory on the PATH, the attacker does not need an exploit. They edit the file. Check directories too. A writable directory on a root-run path can let an attacker replace a file even when the file itself is locked.

Hands-on lab: files and permissions

Run this in a Linux environment you control: a WSL distribution or a VM created for this course. Do not run it on a production server or a shared machine. The second-user section creates an account, so do that only in your own lab VM.

Create and inspect a file

bash
mkdir ~/permlab && cd ~/permlab
echo 'lab secret' > notes.txt && ls -l notes.txt

On Ubuntu 24.04 under WSL, the new file showed -rw-r--r-- with the owner and group named after the account. Your user name, date and group will differ. Compare the mode.

Change the mode

bash
chmod 600 notes.txt && stat -c '%a %U:%G %n' notes.txt
umask

Observed output:

text
600 usurio:usurio notes.txt
0022

Your account name will differ. 600 means only the owner can read and write. 0022 is the umask in the current shell, and the leading zero is part of the octal form.

Now a directory:

bash
mkdir sub && chmod 750 sub && stat -c '%a %n' sub

Observed: 750 sub. The owner has full access, the group can read and enter, and other users get nothing.

Symbolic changes, one at a time, with a read after each:

bash
chmod u=rw,go=r notes.txt && stat -c '%a %A %n' notes.txt
chmod g+w notes.txt && stat -c '%a %A %n' notes.txt
chmod o-r notes.txt && stat -c '%a %A %n' notes.txt

Observed:

text
644 -rw-r--r-- notes.txt
664 -rw-rw-r-- notes.txt
660 -rw-rw---- notes.txt

Each command changed only the bits it named.

See how umask changes new files

Run umask in a subshell so the change does not stay in your session:

bash
(umask 077; touch private.txt; stat -c '%a %A %n' private.txt)
(umask 002; touch shared.txt; mkdir made_dir; stat -c '%a %A %n' shared.txt made_dir)

Observed:

text
600 -rw------- private.txt
664 -rw-rw-r-- shared.txt
775 drwxrwxr-x made_dir

With 077, the file lost every group and other bit. With 002, the group gained write on both the file and the directory. The directory started from 777 and lost only 002.

Test access as a second local user

This step needs an account you can create in your own VM. Run it there only.

bash
sudo useradd -m labuser
sudo -u labuser cat ~/permlab/notes.txt

I did not run these commands. The WSL account needs a password for sudo, and I did not enter one. What to look for: with mode 600, the second command should fail with a Permission denied message, because labuser is neither the owner nor in the group.

Next, relax the file for others:

bash
chmod 644 notes.txt
sudo -u labuser cat ~/permlab/notes.txt

What to look for: the content prints only if labuser can also enter your home directory and ~/permlab. Many distributions create home directories as 755, but some use 750. If a parent directory denies x to other users, the read still fails, even with a readable file. Check with ls -ld ~ ~/permlab. On the Ubuntu 24.04 WSL install I used, ls -ld ~ printed drwxr-x---, which is 750, so a second user would be blocked there even after chmod 644. This is the directory x bit from earlier, in practice.

Search for risky permissions

List world-writable regular files under your home directory, without crossing into other file systems:

bash
find ~ -xdev -type f -perm -o+w 2>/dev/null

In a clean lab this prints nothing. To see the search work, make one file writable on purpose:

bash
chmod 666 ~/permlab/notes.txt
find ~ -xdev -type f -perm -o+w 2>/dev/null
chmod 644 ~/permlab/notes.txt

Observed: the first search printed /home/usurio/permlab/notes.txt. After the fix, the same search printed nothing.

List setuid binaries in a system directory:

bash
find /usr/bin -perm -4000 -type f 2>/dev/null | sort

Observed on Ubuntu 24.04 under WSL, this printed ten files, including /usr/bin/passwd, /usr/bin/sudo, /usr/bin/su, /usr/bin/mount and /usr/bin/umount. Your list depends on the distribution and installed packages. In a review, compare the list with what the package manager says should be setuid. Treat an unexpected entry as a question to answer, not as proof of an attack.

Check the sticky bit on temporary directories:

bash
stat -c '%a %A %n' /tmp /var/tmp

Observed: 1777 drwxrwxrwt for both. The t means users can create files there but cannot delete files that belong to someone else.

Cleanup

bash
rm -rf ~/permlab
sudo userdel -r labuser

userdel -r also deletes the account's home directory. Run it only for the lab account you created.

What the Windows check showed

The same first steps in Git Bash for Windows did not behave like Linux. After chmod 600 notes.txt, stat still reported 644, and later chmod calls did not change the output either. Windows stores access in NTFS access control lists, and Git Bash maps only some of the bits. A Windows lab can teach the commands, but it cannot show what a Linux mode does. Use WSL with a Linux distribution, or a VM, for this article.

Common mistakes

Using 777 to fix a denied error. It works, and it also lets everyone write and execute the file. Find which class is denied and grant only that class.

Forgetting the directory. A readable file can still be unreachable if a parent directory lacks x for the user. Check every directory on the path.

Using chmod -R on a whole tree. Recursive changes often set execute on regular files or remove it from directories. Use find with -type f or -type d to target one kind.

Trusting the mode of a copied file. cp, tar and archive tools may keep or reset modes depending on flags. Check the result with stat.

Reading symbolic modes as absolute. chmod g+w adds one bit. chmod g=w clears read and execute for the group. The difference is easy to miss.

Reaching for root first. Many read and write problems are fixed with group membership or a directory mode, not with a setuid helper or a root shell.

Why this matters in security reviews

A permission review starts with one question: who can change what a privileged process reads or runs? Three findings come up again and again:

  1. Writable files on a privileged path. A config or script read by a root service and writable by a normal account is an escalation waiting for an edit.
  2. Unexpected setuid or setgid binaries. Each one is code that runs with more rights than its caller. Compare the list with a baseline.
  3. Writable directories in a search path or service directory. A user who can create or rename a file there can replace a trusted file, even if the file itself is locked.

When you write up a finding, name the path, the mode, the owner, the group, the process that reads or runs it, and the change that fixes it. Test in your own lab. Do not run these searches against systems you do not administer, and do not use sudo -u on someone else's machine.

How to go further

Once the basic modes are clear, learn access control lists with getfacl and setfacl, which add per-user entries beyond owner, group and other. Read the chattr manual for immutable and append-only flags. Use namei -l /path/to/file to print the mode of every component in a path. It is the quickest way to find the directory that blocks a service.

For the shell habits behind these commands, start with the earlier Field Manual article on Bash basics for security students. The next article, what SSH is and how SSH keys work, covers SSH keys, which depend on the same modes: the private key file must be readable only by its owner, and an SSH client refuses to use a key whose mode is too open.

Least privilege starts with file modes. A process that can write less does less damage when it is wrong, and a file that others cannot change is one less thing to review.

Sources

Sources

  1. GNU Coreutils manual: File permissions
  2. chmod(1) manual page, Linux man-pages
  3. umask(2) manual page, Linux man-pages
  4. chmod, POSIX.1-2024 utility specification (The Open Group)

More in Linux and developer tools

Linux and developer tools

Bash Basics for Security Work

Learn pipes, redirection, variables, loops, exit codes and set -euo pipefail, then use them to count failed logins and hash a folder.

Beginner13 min read

Linux and developer tools

SSH Keys: How They Work and How to Use Them Safely

How SSH host and user keys work, why Ed25519 with a passphrase is the default to use, and how to set up and harden a key login on a lab VM you own.

Beginner11 min read