A computer with one user and no network connection does not need access control. But the moment a second person can log in, or the machine connects to the internet, you need a way to separate what different people and programs are allowed to do. Who can read your files? Who can install software? Who can shut down the machine?
Linux answers these questions with a system that dates back to the original Unix: users, groups, and permission bits. Every file, every process, and every action on the system is governed by this model.
Users Are Numbers
When you log into a Linux system, you type a username like "alice" or "admin." But internally, the kernel does not care about names. It tracks users by number. Every user has a UID -- a user identifier, which is an integer.
| UID | Conventional Meaning |
|---|---|
| 0 | root (superuser) |
| 1-999 | System accounts (services) |
| 1000+ | Regular human users |
The mapping between names and numbers is stored in /etc/passwd. Despite the name, this file does not contain passwords (not anymore -- it did in the 1970s). Each line describes one user:
alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash
The fields, separated by colons, are:
- Username (
alice) - Password placeholder (
x-- actual password is in/etc/shadow) - UID (
1000) - Primary GID (
1000) - Comment / full name (
Alice Smith) - Home directory (
/home/alice) - Login shell (
/bin/bash)
Passwords and /etc/shadow
The actual password hashes live in /etc/shadow, which is readable only by root. This separation exists because /etc/passwd must be world-readable (programs need to look up usernames), but password hashes should not be.
A line in /etc/shadow looks like:
alice:$6$rounds=5000$salt$hash...:19500:0:99999:7:::
The $6$ prefix indicates SHA-512 hashing. The salt is a random string that ensures two users with the same password produce different hashes. The remaining fields control password aging -- when it was last changed, when it expires, and how much warning to give.
Groups
A group is a named collection of users, identified by a GID (group identifier). Groups exist so you can grant permissions to multiple users at once without listing them individually.
Every user has a primary group (set in /etc/passwd) and can belong to additional supplementary groups (set in /etc/group).
The /etc/group file:
developers:x:1001:alice,bob,carol
www-data:x:33:alice
sudo:x:27:alice
Each line has four fields: group name, password placeholder, GID, and a comma-separated list of members.
Check your own groups with:
id
groups
The id command shows your UID, primary GID, and all supplementary groups. This is exactly what the kernel sees when it checks your permissions.
The Root User
UID 0 is root, the superuser. Root bypasses almost all permission checks. Root can read any file, write any file, kill any process, mount filesystems, load kernel modules, and change the system clock. There is no higher authority on a Linux system.
This is both powerful and dangerous. A mistake as root can destroy the system. A compromised root account means an attacker controls everything. This is why modern practice avoids logging in as root directly. Instead, you log in as a normal user and use sudo to run individual commands with root privileges.
sudo apt update # Run this one command as root
sudo -i # Open a root shell (use with caution)
sudo checks /etc/sudoers to determine whether the requesting user is allowed to elevate. On most desktop distributions, the first user created during installation is granted sudo access.
File Permissions
Every file and directory on the system has three sets of permission bits: one for the owner, one for the group, and one for others (everyone else).
Each set has three bits:
| Bit | Letter | On a file | On a directory |
|---|---|---|---|
| Read | r | Can read the file contents | Can list the directory contents |
| Write | w | Can modify the file | Can create/delete files in the directory |
| Execute | x | Can run the file as a program | Can enter (cd into) the directory |
The ls -l command shows permissions:
-rwxr-xr-- 1 alice developers 4096 Jan 18 10:30 script.sh
Reading the permission string -rwxr-xr--:
- First character: file type (
-= regular file,d= directory,l= symlink) - Characters 2-4: owner permissions (
rwx= read, write, execute) - Characters 5-7: group permissions (
r-x= read, execute, no write) - Characters 8-10: others permissions (
r--= read only)
Octal Notation
Each permission bit has a numeric value: read = 4, write = 2, execute = 1. You add them up for each group. The permissions rwxr-xr-- become 754: owner gets 4+2+1=7, group gets 4+0+1=5, others get 4+0+0=4.
You can set permissions with chmod:
chmod 755 script.sh # rwxr-xr-x
chmod 644 document.txt # rw-r--r--
chmod 600 secret.key # rw-------
You can also use symbolic notation:
chmod u+x script.sh # Add execute for owner
chmod g-w file.txt # Remove write for group
chmod o= file.txt # Remove all permissions for others
Changing Ownership
The chown command changes the owner and group:
chown alice:developers file.txt # Set owner and group
chown alice file.txt # Set owner only
chown :developers file.txt # Set group only
Only root can change the owner of a file. A regular user can only change the group to a group they belong to.
How the Kernel Checks Permissions
When a process tries to access a file, the kernel follows a simple algorithm:
- If the process runs as UID 0 (root), allow everything. Check done.
- If the process's UID matches the file's owner UID, use the owner permission bits.
- If the process's GID (or any supplementary GID) matches the file's group GID, use the group permission bits.
- Otherwise, use the others permission bits.
This is a strictly ordered check. If you are the owner, the owner bits apply even if the group bits are more permissive. This occasionally surprises people: a file owned by alice with permissions ---rwxrwx is unreadable by alice, even though both the group and others have full access.
Special Permission Bits
Beyond the basic rwx bits, there are three special bits that modify how files and directories behave.
setuid (Set User ID)
When a program with the setuid bit set is executed, it runs with the UID of the file's owner rather than the UID of the user who launched it. This is how normal users can change their own passwords -- the passwd command is owned by root with setuid set:
ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 Jan 18 10:30 /usr/bin/passwd
Notice the s where the owner's execute bit would be. When alice runs passwd, the process runs with UID 0 (root), giving it permission to write to /etc/shadow. When passwd finishes, the elevated privileges disappear.
setuid is powerful and dangerous. A bug in a setuid-root program can give any user root access. This is why the set of setuid programs on a system is kept deliberately small, and security auditors pay special attention to them.
setgid (Set Group ID)
Similar to setuid, but for the group. On a file, it makes the program run with the file's group. On a directory, it has a different effect: new files created inside the directory inherit the directory's group instead of the creating user's primary group. This is useful for shared project directories.
The Sticky Bit
On a directory, the sticky bit prevents users from deleting files they do not own, even if they have write permission on the directory. The classic example is /tmp:
ls -ld /tmp
drwxrwxrwt 15 root root 4096 Jan 18 10:30 /tmp
The t at the end is the sticky bit. Everyone can create files in /tmp, but you can only delete your own files. Without the sticky bit, anyone with write access to the directory could delete anyone else's files.
Process Credentials
Every process inherits the UID and GID of the user who started it. When Alice's shell (running as UID 1000) runs ls, the ls process also runs as UID 1000. When ls tries to read a directory, the kernel checks UID 1000's permissions.
A process actually carries several IDs:
- Real UID -- the user who started the process
- Effective UID -- the UID used for permission checks (usually the same as real, unless setuid is involved)
- Saved UID -- allows a process to temporarily drop and regain elevated privileges
When a setuid program runs, the effective UID changes to the file owner, but the real UID stays as the invoking user. This is how the program knows who actually ran it.
Why This Matters for Security
The user/group/permission model is the first line of defense on a Linux system. It works because:
Isolation. Each user's files are protected from other users by default. A compromised web server running as www-data (UID 33) cannot read files in /home/alice/ (owned by UID 1000, mode 700).
Least privilege. Services run as dedicated, unprivileged users. The SSH daemon runs as sshd. The web server runs as www-data. If one service is compromised, the attacker gets only that service's permissions, not root.
Audit trail. Every process carries a UID. Logs record which user performed each action. This makes it possible to trace what happened after a security incident.
The model is not perfect. It has no concept of fine-grained capabilities beyond the binary root/non-root distinction. (Linux capabilities and mandatory access control systems like SELinux and AppArmor add more granularity, but those build on top of the basic model.) It does not protect against a careless root user. And it requires discipline -- a single chmod 777 on a sensitive directory can undo all the protection.
But for a system designed in the 1970s, it has proven remarkably durable. Every modern Linux system, from phones to supercomputers, still uses these same UID and GID checks as the foundation of its security.
Essential Commands
id # Show your UID, GID, and groups
whoami # Show your username
ls -la # Show file permissions
chmod 640 file # Set permissions
chown user:group file # Change ownership
passwd # Change your password
sudo command # Run a command as root
su - username # Switch to another user
getent passwd alice # Look up a user
getent group developers # Look up a group
These commands map directly to the concepts in this article. id shows the kernel's view of who you are. ls -la shows the kernel's view of who owns a file. chmod and chown change those values. Everything else in the system -- every permission error, every "access denied" message, every security policy -- traces back to these fundamentals.
Next: What a Shell Actually Is