Understanding Linux File Permissions: Read, Write, and Execute

Learn how Linux file permissions work, what read, write, and execute mean for files and directories, how to read the permission string, and why it matters for security.

Understanding Linux File Permissions: Read, Write, and Execute

Linux file permissions control who can read, write to, or execute each file and directory on the system. Every file has three sets of permissions — one for the file’s owner, one for the owner’s group, and one for all other users. Each set contains three permission bits: read (r), write (w), and execute (x). These nine bits, displayed as a string like -rwxr-xr--, determine exactly who can do what with every file, forming the foundation of Linux’s multi-user security model.

Introduction: Why Every File Has a Passport

In a world where only one person ever uses a computer, file permissions would be unnecessary. Any file could be accessed, modified, or deleted by anyone sitting at the keyboard — and that would be fine, because “anyone” means only one person.

Linux was not designed for that world. Linux descends from Unix, a system built from the ground up to be shared among many users simultaneously — students on a university computer, employees at a company, administrators and regular users on the same machine. On such a system, one user’s files must be protected from other users. The system administrator’s configuration files must be protected from accidental modification. Programs that need special privileges must be controlled carefully. And the whole arrangement must be efficient — no performance penalty for checking permissions millions of times per day.

The solution Unix developed — and Linux inherited — is the file permission system. Every single file and directory on a Linux system carries with it a small but complete description of who is allowed to do what with it. This description is checked every time the file is accessed, modified, or executed, and access is granted or denied based on who is asking and what they are asking to do.

Understanding file permissions is foundational Linux knowledge. It explains why certain operations require sudo, why some files cannot be read, why some programs need the executable bit set before they will run, and how Linux maintains security across multiple users on the same system. This article explains the permission system thoroughly — what the permission bits mean, how the permission string is structured, how ownership works, and how it all fits together to create a coherent security model.

The Three Permission Types

Every permission check in Linux comes down to three questions: Can this entity read this file? Can this entity write to this file? Can this entity execute this file?

Read Permission (r)

On files: Read permission allows the contents of the file to be read. A user with read permission on a file can open it, copy it, and view its contents. A user without read permission cannot open or read the file, even if they know its exact location — they get a “Permission denied” error.

On directories: Read permission on a directory allows listing its contents — seeing what files and subdirectories it contains. Without read permission on a directory, you cannot run ls on it to see what is inside. You might know a file exists there (if someone tells you its name), but you cannot discover its name by browsing the directory.

Read is the most fundamental permission. It is what allows information to flow from a file to a user.

Write Permission (w)

On files: Write permission allows modifying the file’s contents — editing it, appending to it, truncating it, or overwriting it entirely. Write permission also allows deleting the file in most circumstances (though this also depends on the directory containing the file, as explained below).

On directories: Write permission on a directory allows creating new files in the directory, deleting files from the directory, and renaming files within the directory. This is a crucial and often surprising distinction: the permission to delete a file is determined by the write permission on the directory containing the file, not by the permissions on the file itself.

This means: if you have write permission on a directory, you can delete any file in that directory even if you cannot read the file’s contents and even if you do not own the file. And conversely, if you own a file but do not have write permission on the directory containing it, you cannot delete it. Permissions on files and directories interact in ways that reward careful thought.

Execute Permission (x)

On files: Execute permission allows running the file as a program. Without execute permission, a shell script or compiled binary cannot be executed — attempting to run it produces a “Permission denied” error. This is why, when you write a shell script, you must explicitly make it executable with chmod +x sc.ript.sh before you can run it.

The execute bit has no effect on files that are not programs. Setting execute permission on a text document or an image does not make it runnable — the kernel will try to execute it, fail because it is not a valid program format, and report an error.

On directories: Execute permission on a directory (often called the “search bit” or “traverse bit”) allows traversing the directory — accessing files within it by name, changing into it with cd, and accessing subdirectories through it. Without execute permission on a directory, you cannot cd into it and cannot access any of its contents even if you know their names.

The combination of directory permissions produces interesting effects:

  • r without x on a directory: You can list the directory’s contents (see filenames) but cannot access any of those files. You can see the names but cannot open anything.
  • x without r on a directory: You can access files if you know their exact names but cannot list the directory to discover what is there. This is the “secret room” pattern — you can open a specific door if you know exactly where it is, but you cannot browse the available doors.
  • r + x on a directory (the standard case): You can both list contents and access files within the directory.
  • r + x + w on a directory: Full control — list, access, create, delete, and rename.

The Three Permission Classes

Each of the three permissions (read, write, execute) exists for three distinct classes of users, creating nine permission bits total.

Owner (User)

The owner of a file is the user account under whose identity the file was created. When you create a file, you are its owner. When a program running as root creates a file, root is its owner. The owner permissions control what the owner can do with the file.

The owner is sometimes called “user” in technical contexts (which is why chmod uses u to refer to the owner, potentially confusingly). In this article, “owner” refers to this class to avoid confusion with “user” meaning any system user.

Group

Every file is associated with exactly one group — a named collection of user accounts. When a file is created, it is assigned the primary group of the creating user (though this can be configured differently). Group permissions control what members of the associated group can do with the file.

Groups allow sharing files among a specific set of users without making them world-accessible. A team of developers might all belong to a developers group, allowing them all to read and write shared project files while others outside the group see only restricted access.

Others (World)

Others refers to all users who are neither the file’s owner nor members of the file’s associated group. Other permissions control what everyone else on the system can do with the file.

When a file needs to be accessible to any user on the system (like a system command in /usr/.bin that all users need to run), the “others” execute and read bits are set. When a file should be strictly private, the “others” permissions are set to none.

Reading the Permission String

When you run ls -l, each file is shown with a 10-character string at the beginning of the line. Understanding this string is the key to reading file permissions at a glance.

Bash
$ ls -la ~/Documents
total 40
drwxr-xr-x  5 sarah developers 4096 Feb 18 09:22 .
drwxr-xr-x 25 sarah sarah      4096 Feb 17 20:15 ..
-rw-r--r--  1 sarah sarah      8192 Feb 16 11:34 report.pdf
-rwxr-x---  1 sarah developers 2048 Feb 15 16:22 pro.cess.sh
-rw-rw-r--  1 sarah developers 4096 Feb 18 08:00 shared_notes.txt
drwxr-xr-x  3 sarah sarah      4096 Feb 14 10:00 archive

Let us dissect the permission string character by character using -rwxr-x--- as an example:

Character 1: File type indicator

The first character indicates what type of filesystem object this is:

  • - — a regular file
  • d — a directory
  • l — a symbolic link
  • c — a character device file (in /dev)
  • b — a block device file (in /dev)
  • p — a named pipe
  • s — a socket

Characters 2–4: Owner permissions

The second, third, and fourth characters show the owner’s permissions:

  • Position 2: r if the owner can read, - if not
  • Position 3: w if the owner can write, - if not
  • Position 4: x if the owner can execute, - if not

So rwx means the owner can read, write, and execute. rw- means read and write but not execute. r-- means read only. --- means no permissions at all.

Characters 5–7: Group permissions

The fifth, sixth, and seventh characters show permissions for the file’s associated group, following the same r/w/x pattern.

Characters 8–10: Others permissions

The eighth, ninth, and tenth characters show permissions for all others, again following the r/w/x pattern.

Parsing the Examples

Let us parse each file from the ls -la output above:

-rw-r--r-- 1 sarah sarah report.pdf

  • - — regular file
  • rw- — owner (sarah) can read and write, not execute
  • r-- — group (sarah) can read only
  • r-- — others can read only

This is a typical permissions configuration for a document: the owner can edit it, and everyone else can read it. The group and other permissions being identical here is because the group name is also “sarah” (the user’s primary group).

-rwxr-x--- 1 sarah developers pro.cess.sh

  • - — regular file
  • rwx — owner (sarah) can read, write, and execute
  • r-x — group (developers) can read and execute but not write
  • --- — others have no permissions at all

This is a script that sarah can modify and run, members of the developers group can run but not modify, and everyone else cannot access at all.

-rw-rw-r-- 1 sarah developers shared_notes.txt

  • - — regular file
  • rw- — owner (sarah) can read and write
  • rw- — group (developers) can read and write
  • r-- — others can only read

A shared working document where both sarah and all developers can edit it, but other users can only read it.

drwxr-xr-x 3 sarah sarah archive

  • d — directory
  • rwx — owner (sarah) can read, write, and traverse (full control of directory)
  • r-x — group (sarah) can list and traverse but not create/delete files
  • r-x — others can list and traverse but not create/delete files

This is the standard permission for a directory that should be readable by everyone but only writable by the owner.

Numeric (Octal) Permission Notation

In addition to the symbolic notation (rwxr-xr--), Linux permissions are commonly represented as a three-digit number. This numeric notation (called octal notation) is used extensively with the chmod command.

How Octal Notation Works

Each permission bit has a numeric value:

  • Read (r) = 4
  • Write (w) = 2
  • Execute (x) = 1
  • No permission (-) = 0

The permissions for each class (owner, group, others) are calculated by summing the values of the set bits:

PermissionrwxNumeric Value
rwx4217
rw-4206
r-x4015
r--4004
-wx0213
-w-0202
--x0011
---0000

A complete permission set is expressed as three digits — one for owner, one for group, one for others:

  • 755 = rwxr-xr-x (7=rwx for owner, 5=r-x for group, 5=r-x for others)
  • 644 = rw-r--r-- (6=rw- for owner, 4=r– for group, 4=r– for others)
  • 600 = rw------- (6=rw- for owner, 0=— for group, 0=— for others)
  • 700 = rwx------ (7=rwx for owner, 0=— for group, 0=— for others)

Common Permission Patterns and Their Meanings

Certain permission combinations appear repeatedly because they serve common purposes:

644 (`rw-r–r–) — The standard permission for regular files. The owner can read and write; everyone else can only read. Appropriate for documents, images, and most personal files that you do not mind others reading.

600 (rw-------) — Private file. Only the owner can read and write; all others have no access. Appropriate for private documents, SSH private keys, and configuration files containing passwords.

755 (rwxr-xr-x) — Standard permission for executable programs and public directories. The owner can read, write, and execute; others can read and execute but not write. Appropriate for commands in /usr/bin, public web directories, and scripts meant for general use.

700 (rwx------) — Private executable or directory. Only the owner has any access. Appropriate for personal scripts or directories containing sensitive material.

777 (rwxrwxrwx) — World-writable. Everyone has full read, write, and execute access. Generally a security risk for most files — avoid in production environments. Appropriate only for shared temporary directories in specific, controlled situations.

750 (rwxr-x---) — Executable accessible to the owner and their group but not others. Appropriate for scripts meant only for a specific team.

640 (rw-r-----) — File readable by owner and group, inaccessible to others. Appropriate for configuration files shared within a team but not publicly readable.

Special Permission Bits

Beyond the standard nine permission bits, Linux has three special permission bits that serve specific purposes.

SetUID (SUID) — Run as the File’s Owner

The SetUID bit (set user ID) on an executable file means: when any user runs this program, it runs with the permissions of the file’s owner, not the permissions of the user running it.

The most important example of SetUID is the passwd command, which allows users to change their own passwords. Password hashes are stored in /etc/.shadow, a file readable and writable only by root. For a regular user to change their password, they need to modify /etc/.shadow — but giving regular users write access to /etc/.shadow would be a catastrophic security hole.

The solution: the passwd executable is owned by root and has the SetUID bit set. When any user runs passwd, the program temporarily runs with root’s privileges, allowing it to modify /etc/.shadow. The program is carefully written to only change the calling user’s own password entry — it uses the elevated privileges responsibly.

In ls -l output, SetUID appears as s in place of the owner’s execute bit:

Bash
-rwsr-xr-x 1 root root 59976 Mar 22  2023 /usr/.bin/passwd

The s in position 4 (where x would normally be for the owner) indicates SetUID.

If the file does not have execute permission for the owner, the SetUID bit appears as S (capital) rather than s — indicating the bit is set but the execute permission is not, which is an unusual and generally unintended state.

Security note: SetUID programs are a significant security responsibility. A SetUID program owned by root that has a security bug can be exploited to gain root access. This is why the number of SetUID-root programs on a Linux system is deliberately kept small.

SetGID (SGID) — Run as the File’s Group

The SetGID bit (set group ID) has two different effects depending on whether it is applied to a file or a directory.

On executable files: Similar to SetUID, SetGID causes the program to run with the permissions of the file’s group rather than the running user’s group. Less commonly used than SetUID but occasionally found on system utilities.

In ls -l output, SetGID appears as s in place of the group’s execute bit:

Bash
-rwxr-sr-x 1 root tty 35192 Feb  8  2023 /usr/.bin/write

On directories: SetGID on a directory means that new files and subdirectories created within that directory automatically inherit the directory’s group rather than the creating user’s primary group. This is extremely useful for collaborative directories — if a projects directory is owned by the developers group and has SetGID set, any file created in it by any developer automatically belongs to the developers group, making it immediately accessible to all team members.

drwxrwsr-x 5 root developers 4096 Feb 18 09:22 /shared/projects

Sticky Bit — Protect Files in Shared Directories

The sticky bit on a directory means that only the file’s owner, the directory’s owner, or root can delete or rename files within that directory, even if the directory itself is world-writable.

The most important application is /tmp. The /tmp directory is world-writable — any user or program can create files there. Without the sticky bit, any user could also delete any other user’s files in /tmp. With the sticky bit set, each user can only delete their own files in /tmp, while still being able to create files freely.

Bash
drwxrwxrwt 32 root root 20480 Feb 18 14:33 /tmp

The t in the last position of the permission string indicates the sticky bit is set.

Ownership: Users and Groups

File permissions only make sense in the context of ownership — who is the file’s owner, and what group is it associated with?

How Ownership Works

Every file has exactly one owner (a user account) and exactly one associated group. When a file is created, it is owned by the user who created it and associated with that user’s primary group (the group listed in /etc/.passwd for that user).

The ownership information is visible in ls -l output in the third and fourth columns:

Bash
-rw-r--r-- 1 sarah developers 8192 Feb 16 report.pdf

Here, sarah is the owner and developers is the associated group.

Checking Your Groups

Bash
$ groups
sarah adm cdrom sudo audio video plugdev

This shows all groups the current user belongs to. Group memberships determine which group permissions apply to you when you access files owned by those groups.

Bash
$ id
uid=1000(sarah) gid=1000(sarah) groups=1000(sarah),4(adm),27(sudo),29(audio)

id shows more detail including numeric IDs.

Changing Ownership

The chown command changes a file’s owner and/or group:

Bash
$ sudo chown newowner filename
$ sudo chown newowner:newgroup filename
$ sudo chown :newgroup filename          # Change only the group
$ sudo chown -R newowner:newgroup dir/   # Recursive (for directories)

Changing file ownership requires root privileges — you cannot give your files to another user without administrator access (this prevents users from hiding files by assigning them to another user).

Changing Group Association

The chgrp command changes only the group association:

Bash
$ chgrp developers shared_project.txt
$ sudo chgrp -R developers project/

Regular users can change a file’s group to any group they themselves belong to. Changing to a group you are not a member of requires root privileges.

How Permissions Are Checked: The Access Decision

When a user tries to access a file, the kernel performs a specific check to decide whether to allow or deny the access. Understanding this check process clarifies several non-obvious behaviors.

The Permission Check Algorithm

The kernel checks permissions in order:

  1. Is the user root? If yes, almost all permissions are bypassed — root can read, write, and (with some caveats) execute any file regardless of permissions.
  2. Is the user the file’s owner? If yes, the owner permission bits apply. Only the owner bits are checked — group and others bits are irrelevant for the owner.
  3. Is the user a member of the file’s group? If yes, the group permission bits apply. Owner bits are not checked (the user was not the owner, so we move on to group).
  4. Otherwise: The others permission bits apply.

This sequential check has an important implication: if you are the file’s owner, only the owner permissions apply — even if the group permissions are more permissive.

Consider a file with permissions ---rwxrwx owned by alice, group developers. If alice (the owner) tries to read this file, she is denied — even though the group and others permissions allow everything. The kernel sees that alice is the owner, applies the owner permissions (---), finds no read permission, and denies access. This can seem counterintuitive but follows directly from the check algorithm.

In practice, you would rarely intentionally configure permissions this way. It is a reminder that the owner class does not represent “you” in all cases — it represents the specific user account that owns the file.

Why Root Bypasses Permissions

Root bypasses most permission checks because root needs to be able to manage any file on the system — backing up files, repairing a broken installation, recovering from a mistake. A security model where even root could not access certain files would make system administration impossible.

The exception is execute permission: root cannot execute a file that has no execute bits set for anyone. A file with permissions ---------- (no permissions for anyone) cannot be executed even by root. This is a deliberate design choice — root should not accidentally execute non-executable data as a program.

The umask: Default Permissions for New Files

When you create a new file, Linux does not use some arbitrary default permission — it calculates the permission based on a setting called the umask (user file creation mask).

How umask Works

The umask is a mask that is subtracted from maximum permissions to produce the default permissions for new files and directories.

  • Maximum permissions for new regular files: 666 (rw-rw-rw-) — execute is never set by default for files
  • Maximum permissions for new directories: 777 (rwxrwxrwx)

The umask specifies which bits to remove from these maximums. The most common umask is 022:

Bash
666 (max file permissions)
- 022 (umask)
= 644 (default file permissions: rw-r--r--)

777 (max directory permissions)
- 022 (umask)
= 755 (default directory permissions: rwxr-xr-x)

Another common umask is 002 (used for group-collaborative environments):

Bash
666 - 002 = 664 (rw-rw-r--)
777 - 002 = 775 (rwxrwxr-x)

Checking and Setting umask

Bash
$ umask
0022
Bash
$ umask 002        # Change umask for current shell session

To make the change permanent, add umask 002 to your ~/.bash.rc file.

Why umask Matters

The umask explains why files you create have the permissions they do. If your umask is 022, new files are created as 644 (readable by all, writable only by you) and new directories as 755 (accessible by all, writable only by you). If you want new files in a project directory to be group-writable, setting umask 002 in your session (or for your login shell) changes the default for all files you create.


Practical Permission Scenarios

Scenario 1: A Private SSH Key

SSH private keys must be protected from any access by other users. If a private key file has permissions that allow group or others to read it, the SSH client refuses to use it:

Bash
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/home/sarah/.ssh/.id_rsa' are too open.

The correct permissions for an SSH private key:

Bash
$ chmod 600 ~/.ssh/.id_rsa

After this: -rw------- — only the owner can read or write the key.

Scenario 2: A Shared Project Directory

A team of developers needs a shared directory where everyone can create, modify, and read each other’s files:

Bash
$ sudo mkdir /projects/team_alpha
$ sudo chown sarah:developers /projects/team_alpha
$ sudo chmod 2775 /projects/team_alpha

Breaking down 2775:

  • The 2 prefix sets the SetGID bit (new files inherit the developers group)
  • 7 = rwx for owner (sarah)
  • 7 = rwx for group (developers)
  • 5 = r-x for others (can read and traverse but not modify)

Now all developers can create, read, and delete files. New files automatically belong to the developers group. Non-team users can see the directory and read files but not create or delete.

Scenario 3: A Configuration File with Secrets

A configuration file containing a database password should be readable only by the application’s service account and root:

Bash
$ sudo chown appuser:appuser /etc/.myapp/database.conf
$ sudo chmod 600 /etc/.myapp/database.conf

Result: -rw------- — only appuser and root can read the sensitive configuration.

Scenario 4: A Web Server Document Root

Files in a web server’s document root need to be readable by the web server process (running as www-data) but should not be world-writable (to prevent unauthorized modification):

Bash
$ sudo chown -R developer:www-data /var/www/html
$ sudo chmod -R 750 /var/www/html
$ sudo find /var/www/html -type f -exec chmod 640 {} \;

This sets directories to 750 (owner full access, www-data group can read and traverse) and files to 640 (owner can read/write, www-data group can read). The web server can serve files but cannot modify them, and others have no access.

Permission Troubleshooting

“Permission Denied” — Diagnosing the Cause

When you encounter a “Permission denied” error, the diagnostic process is straightforward:

Step 1: Check the file’s permissions:

Bash
$ ls -la /path/to/file

Step 2: Check your identity:

Bash
$ whoami
$ id

Step 3: Compare your identity to the file’s owner and group. Are you the owner? Are you in the group? If neither, only others permissions apply.

Step 4: Look at the relevant permission bits for your relationship to the file and determine whether they allow what you are trying to do.

Step 5: Check parent directory permissions. Even if a file has permissive permissions, if its parent directory does not have execute permission for you, you cannot access it.

Common Permission Problems and Solutions

ProblemLikely CauseSolution
Cannot read a fileMissing read permissionchmod o+r file or ask owner to share
Cannot edit a fileMissing write permissionchmod u+w file (if owner)
Script won’t runMissing execute permissionchmod +x sc.ript.sh
Cannot enter directoryMissing execute bit on directorychmod +x directory/
Cannot create files in directoryMissing write on directorychmod u+w directory/ (if owner)
Cannot delete file you ownParent directory not writableCheck and fix parent directory permissions
SSH key errorKey too permissivechmod 600 ~/.ssh/.id_rsa
Web server 403 errorFile not readable by web serverchmod o+r file or adjust group

Reading Permissions at a Glance: A Reference

StringOctalMeaning
----------000No permissions for anyone
-r--------400Owner read only
-rw-------600Owner read + write (private file)
-rwx------700Owner full access (private executable)
-rw-r--r--644Owner rw, group r, others r (standard file)
-rwxr-xr-x755Owner full, group/others r+x (standard executable)
-rw-rw-r--664Owner + group rw, others r (group-writable file)
-rwxrwxr-x775Owner + group full, others r+x (group-writable executable)
-rwxrwxrwx777Everyone full (world-writable — avoid)
drwxr-xr-x755Standard directory
drwxrwxr-x775Group-writable directory
drwxrwxrwt1777World-writable with sticky bit (/tmp)
drwxrwsr-x2775Group directory with SetGID (collaborative)

Conclusion: Permissions as a Security Language

Linux file permissions are a compact, elegant language for expressing security policy. The nine bits representing read, write, and execute for owner, group, and others — together with the special bits for SetUID, SetGID, and sticky — encode a complete access control system that is simultaneously simple enough to understand intuitively and powerful enough to express complex multi-user sharing arrangements.

Once you can read the permission string drwxr-xr-x as naturally as you read a word, you can immediately understand the access policy for any file or directory you encounter. Once you understand the relationship between the three permission classes and the ownership system, “Permission denied” errors become diagnostic puzzles with clear solutions rather than mysterious obstacles.

The permission system is one of Linux’s foundational security mechanisms. Understanding it deeply — not just what commands to use, but why the system is designed the way it is — makes you a more capable, more confident, and more secure Linux user. The next article covers the chmod command in depth, giving you the practical tools to set and modify permissions to achieve exactly the security policies you need.

Share:
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments

Discover More

What Is a Device Manager and How Does It Help Your OS?

Learn what Device Manager is and how it helps your operating system manage hardware. Discover…

Working with Strings in Python for Data Cleaning

Working with Strings in Python for Data Cleaning

Master Python string methods for data cleaning. Learn to clean, transform, and validate text data…

What Is Plug and Play Technology?

What Is Plug and Play Technology?

Learn what Plug and Play technology is, how operating systems automatically detect and configure hardware…

Polymorphism Explained: Virtual Functions and Dynamic Binding

Polymorphism Explained: Virtual Functions and Dynamic Binding

Master C++ polymorphism with virtual functions and dynamic binding. Learn runtime behavior, vtables, and write…

What is Batch Learning?

Learn what batch learning is, its advantages, applications and best practices. A comprehensive guide to…

Kirchhoff's Voltage Law Explained: The Energy Loop Principle

Kirchhoff’s Voltage Law Explained: The Energy Loop Principle

Master Kirchhoff’s Voltage Law (KVL), the fundamental principle that voltages around any closed loop sum…

Click For More
0
Would love your thoughts, please comment.x
()
x