| | |

LFCA 24 ๐Ÿง Understanding File Permissions

Every file and directory on a Linux system carries a set of permission bits. These bits decide who can read the file, who can write to it, and who can execute it. They are the mechanism that enforces the separation between users, and they are checked on every file operation the kernel performs. When you run ls -l and see something like -rw-r--r--, you are looking at three groups of three bits each โ€” one group for the owner, one for the group, and one for everyone else. Understanding what those bits mean, how they combine, and what happens when they are wrong is the foundation of Linux security and the prerequisite for every chmod, chown, and access-control decision that follows. This chapter covers the permission model from the ground up: the three permission types, the three identity classes, how they combine for files and for directories, how the numeric and symbolic notations work, and the special bits that go beyond the basic nine.

Key point: Linux permissions are three bits for each of three identity classes โ€” read, write, and execute for the owner, the group, and others. For files, read means “view contents,” write means “modify contents,” and execute means “run as a program.” For directories, the meanings are different: read means “list entries,” write means “create or delete entries,” and execute means “traverse into or through the directory.” The numeric notation maps read=4, write=2, execute=1, and each class’s bits are summed into a single octal digit โ€” so 755 is rwxr-xr-x. Beyond these nine bits are three special bits โ€” setuid, setgid, and sticky โ€” that change how execution and deletion behave.


The three permission types

Every permission bit has one of three meanings, and the meaning depends on whether the object is a file or a directory. This is the single most important distinction in the permission model, and confusing the two is the most common source of misunderstanding.

Read (r). On a file, read grants the ability to view the file’s contents โ€” cat, less, grep, opening it in an editor. On a directory, read grants the ability to list the entries in the directory โ€” ls returns the names of the files inside. Without read on a directory, ls fails even if you know the names of the files, because listing requires reading the directory’s own data structure, which contains the mapping from names to inodes.

Write (w). On a file, write grants the ability to modify the file’s contents โ€” editing, appending, truncating. On a directory, write grants the ability to create, delete, and rename entries within that directory. Note the asymmetry: deleting a file is a write operation on the directory, not on the file. A file with mode 444 (read-only for everyone) can be deleted by anyone who has write permission on its parent directory, because deletion is an operation on the directory entry, not the file contents. This surprises people, and it is the source of the “how did my read-only file get deleted?” question.

Execute (x). On a file, execute grants the ability to run the file as a program โ€” the kernel will load it and start a process. For interpreted scripts, execute permission plus a shebang line (#!/bin/bash) allows the kernel to invoke the interpreter. On a directory, execute grants the ability to traverse the directory โ€” to access files inside it by name, to cd into it, to use it as a component of a path. Without execute on a directory, you cannot access any file within it, even if you know the exact path and have full permissions on the file itself. A directory with read but not execute allows listing the names but not accessing the contents, which is an unusual but valid configuration.

Why the directory meanings matter more than they seem. Most permission problems in practice involve directories, not files. A web server that cannot traverse a directory cannot serve files from it. A user who cannot write to a directory cannot create files in it, regardless of the files’ own permissions. A script that cannot be executed cannot be run, even if it is readable. The directory’s permission bits are the gate, and the file’s bits are the lock on the door behind it.

Why the execute bit on a directory is required for path resolution. When you access /home/alice/notes.txt, the kernel traverses /, then home, then alice, checking execute permission on each directory along the way. If execute is missing on any component, the traversal fails with “Permission denied” โ€” even if the target file is world-readable. This is why directory execute is sometimes called “search” permission; it is the ability to search for names within the directory.


The three identity classes

Every file has an owner and a group. The permission bits are divided into three sets, one for each identity class that the kernel checks.

Owner (u for user). The first set of three bits applies to the file’s owner โ€” the user whose UID matches the file’s owner UID. The owner is set at file creation (to the creating user) and can be changed with chown. The owner usually has the most permissions, but not necessarily โ€” a file can be owned by a user with fewer permissions than the group or others, though this is unusual.

Group (g). The second set applies to the file’s group โ€” the group whose GID matches the file’s group GID, and to which the current process belongs. Remember from LFCA 21 that a process can belong to multiple groups, and the kernel checks all of them. If the file’s group matches any of the process’s groups โ€” primary or supplementary โ€” the group permissions apply.

Others (o). The third set applies to everyone else โ€” any process whose UID is not the owner and whose groups do not include the file’s group. This is the catch-all class, and its permissions are often the most restrictive.

Why the kernel checks in order. The kernel evaluates the classes in order: owner first, then group, then others. The first match wins, and the remaining classes are not consulted. This means that if a user is the owner and the owner has no permissions, the user gets no permissions โ€” even if the “others” class grants read. The kernel does not fall through. This is a common source of confusion: “but the file is world-readable, why can’t I read it?” โ€” because you are the owner, and the owner bits deny it, and the kernel stops there.

Why the group match is by GID list, not by primary group alone. A process carries a set of GIDs โ€” its primary group and any supplementary groups. If the file’s group matches any of them, the group class applies. This is why adding a user to a supplementary group grants access to files owned by that group, without changing the user’s primary group.

Why “others” is not a fallback. It is tempting to think of “others” as “everyone who did not match the owner or group.” That is correct, but the important consequence is that narrowing “others” does not affect the owner or the group. A file with mode 700 is fully accessible to the owner and completely inaccessible to everyone else. A file with mode 770 adds group access. A file with mode 777 grants everyone everything. The classes are independent, and each is checked only if the previous ones did not match.


Reading ls -l output

The ls -l command prints the permission string, the owner, the group, and other metadata. Reading it correctly is the first practical skill.

$ ls -l notes.txt
-rw-r--r-- 1 alice developers 1024 Mar 15 10:22 notes.txt

The first character is the file type. - is a regular file, d is a directory, l is a symbolic link, c is a character device, b is a block device, s is a socket, and p is a named pipe. The next nine characters are the permission bits, in three groups of three: owner, group, others. In this example, the owner has rw-, the group has r--, and others have r--. The owner is alice, the group is developers, the size is 1024 bytes, the date is March 15, and the name is notes.txt.

The numeric equivalent. Each group of three bits maps to an octal digit. Read is 4, write is 2, execute is 1. Sum the bits in each group. rw- is 4+2+0 = 6. r-- is 4+0+0 = 4. So rw-r--r-- is 644. The full mode is 644, often written as 0644 with a leading zero. Similarly, rwxr-xr-x is 4+2+1, 4+0+1, 4+0+1 โ€” 755. And rwx------ is 700.

Why the leading zero matters in some contexts. Commands like chmod accept both 644 and 0644. The leading zero is sometimes required when a special bit is set โ€” 4755 for setuid, 2775 for setgid, 1777 for sticky. The four-digit form is the explicit way to express all twelve bits (three special plus nine regular), and it is the safer habit.

Why the file type character matters for interpretation. The same permission string means different things for a file and a directory. drwxr-xr-x is a directory where the owner can read, write, and traverse, and group and others can read and traverse. -rwxr-xr-x is a file that the owner can read, write, and execute, and group and others can read and execute. The bits are the same; the object type changes the meaning.

Why ls -l shows the owner and group by name. The file stores UIDs and GIDs, not names. ls -l looks up the names in /etc/passwd and /etc/group. If a UID has no matching entry โ€” a stale UID โ€” ls shows the number instead. ls -ln forces numeric output regardless, which is useful when names are ambiguous or when scripting.


Numeric and symbolic notation

chmod accepts two notations: numeric (octal) and symbolic. Both set the same bits, and the choice is a matter of context and clarity.

Numeric notation uses three or four octal digits. Each digit encodes one class’s permissions. 755 is rwxr-xr-x. 644 is rw-r--r--. 600 is rw-------. The notation is compact and unambiguous, and it is the standard for setting a known mode from scratch.

chmod 755 script.sh
chmod 644 document.txt
chmod 600 private.key

Symbolic notation uses letters and operators. The letters are u (owner), g (group), o (others), and a (all three). The operators are + (add), - (remove), and = (set exactly). The permissions are r, w, x, and the special bits s, t.

chmod u+x script.sh         # add execute for owner
chmod go-w file.txt         # remove write for group and others
chmod a+r document.txt      # add read for everyone
chmod u=rw,g=r,o= file.txt  # set exact permissions

Why symbolic is better for incremental changes. When you want to add execute permission without touching the other bits, chmod +x or chmod u+x expresses the intent directly. The numeric equivalent would require knowing the current mode, computing the new one, and setting it โ€” and if the current mode was not what you thought, you would silently change unrelated bits. Symbolic notation changes only what you specify.

Why numeric is better for exact modes. When you want a file to have exactly 600 regardless of its current state, chmod 600 is the direct expression. Symbolic notation would require chmod u=rw,go= to achieve the same result, which is more verbose. Both are correct; the choice depends on whether the operation is incremental or absolute.

The X special case. chmod +X (capital X) adds execute permission only if the file is a directory or already has execute permission for some class. This is useful for recursive operations on trees that contain both files and directories: chmod -R a+rX adds read for everyone and execute only where appropriate, without making every file executable.


Permission meanings for directories

The directory permission model is different enough from the file model that it deserves its own treatment. The three bits mean something else, and the combinations produce behaviors that are not obvious from the file case.

ModeDirectory behavior
r--Can list names, cannot access contents
r-xCan list names and access contents by name
-wxCan access contents if name is known, cannot list
--xCan access contents if name is known, cannot list
rwxFull access
rw-Can create and delete entries, cannot list or traverse

The combinations that matter in practice are r-x (the normal readable directory), --x (the “execute-only” directory that lets someone access a file by known name without being able to list the contents), and rwx (full access). The mode rw- on a directory is unusual and mostly useless: you can create and delete entries by name, but you cannot list them or traverse into subdirectories, so you have to know the names in advance.

Why --x on a directory is useful. A web server’s document root might be --x for others, so that a client can request /index.html and get it, but cannot list the directory and discover what other files exist. The web server knows the filename from the request; the client cannot enumerate. This is a common hardening technique, and it depends on the directory execute bit meaning “traverse” rather than “list.”

Why deleting a file depends on the directory, not the file. When you rm file.txt, the kernel removes the directory entry that maps file.txt to its inode. That is a write operation on the parent directory. The file’s own permissions are irrelevant to the deletion. A file with mode 444 can be deleted if the directory has write permission. This is why rm on a read-only file does not prompt for confirmation by default in most shells โ€” the kernel does not consider the file’s mode.

Why the sticky bit changes deletion. The sticky bit (t) on a directory restricts deletion: only the file’s owner, the directory’s owner, or root can delete a file within the directory, regardless of write permission on the directory. This is what makes /tmp safe โ€” mode 1777 grants everyone write, but the sticky bit prevents one user from deleting another user’s files. Without the sticky bit, /tmp with mode 777 would let anyone delete anyone else’s temporary files.

Why the execute bit is checked on every path component. To open /home/alice/documents/report.txt, the kernel traverses /, home, alice, and documents, checking execute on each. If alice has mode 700, then group and others cannot traverse into it, so they cannot reach documents or report.txt regardless of those objects’ permissions. The most restrictive directory in the path determines the effective access.


Special permission bits

Beyond the nine basic bits, three special bits change the behavior of execution and deletion. They occupy the position before the nine, and they are expressed as a fourth octal digit or as s and t in symbolic notation.

Setuid (s on the owner’s execute position). When set on an executable file, the process that runs it gains the file owner’s UID as its effective UID, rather than the invoking user’s. This is how passwd works: a normal user runs it, but the process temporarily runs as root, which is what allows it to write to /etc/shadow. Setuid is displayed as s where the owner’s execute bit would be, or S if the execute bit is not set (which is a misconfiguration โ€” the setuid bit has no effect without execute).

Setgid (s on the group’s execute position). On an executable file, setgid works like setuid but for the group: the process runs with the file’s group as its effective GID. On a directory, setgid has a different and very useful effect: files created inside the directory inherit the directory’s group rather than the creator’s primary group. This is how shared project directories work โ€” several users create files, and every file belongs to the same group, so the group’s permissions apply uniformly. Setgid is displayed as s in the group’s execute position, or S if execute is missing.

Sticky bit (t on the others’ execute position). On a directory, the sticky bit restricts deletion as described above: only the file owner, the directory owner, or root can delete or rename entries within the directory. On modern Linux systems, the sticky bit on a file has no effect (it was historically used to keep a program in swap, but that behavior is obsolete). The sticky bit is displayed as t in the others’ execute position, or T if execute is missing. The classic example is /tmp, which has mode 1777: rwxrwxrwt.

Why the special bits are displayed with s/S and t/T. The uppercase form signals that the special bit is set but the corresponding execute bit is not, which means the special bit is not functioning as intended. rwSr--r-- has setuid set but execute off, so the setuid behavior does not apply. This is almost always a mistake, and the uppercase letter is the signal to fix it.

Why the numeric forms are 4xxx, 2xxx, and 1xxx. Setuid is 4000, setgid is 2000, sticky is 1000. A directory with setgid and full permissions is 2775. A directory with sticky and full permissions is 1777. The four-digit form combines them: 6755 would be setuid plus setgid plus 755.


Complete Example Session

# ============================================
# PART 1: READING PERMISSIONS
# ============================================

touch file.txt
ls -l file.txt
# -rw-r--r-- 1 alice alice 0 Mar 15 10:00 file.txt
#  โ”‚โ””โ”ฌโ”˜โ””โ”ฌโ”˜โ””โ”ฌโ”˜
#  โ”‚ โ”‚  โ”‚  โ””โ”€โ”€ others: r--
#  โ”‚ โ”‚  โ””โ”€โ”€โ”€โ”€โ”€ group:  r--
#  โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ owner:  rw-
#  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ type:   regular file

# ============================================
# PART 2: NUMERIC NOTATION
# ============================================

chmod 755 file.txt
ls -l file.txt
# -rwxr-xr-x 1 alice alice 0 Mar 15 10:00 file.txt

chmod 644 file.txt
ls -l file.txt
# -rw-r--r-- 1 alice alice 0 Mar 15 10:00 file.txt

chmod 600 file.txt
ls -l file.txt
# -rw------- 1 alice alice 0 Mar 15 10:00 file.txt

# ============================================
# PART 3: SYMBOLIC NOTATION
# ============================================

chmod u+x file.txt
ls -l file.txt
# -rwx------ 1 alice alice 0 Mar 15 10:00 file.txt

chmod go+r file.txt
ls -l file.txt
# -rwxr--r-- 1 alice alice 0 Mar 15 10:00 file.txt

chmod a-x file.txt
ls -l file.txt
# -rw-r--r-- 1 alice alice 0 Mar 15 10:00 file.txt

# ============================================
# PART 4: DIRECTORY PERMISSIONS
# ============================================

mkdir testdir
ls -ld testdir
# drwxr-xr-x 2 alice alice 4096 Mar 15 10:00 testdir
#  โ”‚โ””โ”ฌโ”˜โ””โ”ฌโ”˜โ””โ”ฌโ”˜
#  โ”‚ โ”‚  โ”‚  โ””โ”€โ”€ others: r-x (list + traverse)
#  โ”‚ โ”‚  โ””โ”€โ”€โ”€โ”€โ”€ group:  r-x
#  โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ owner:  rwx
#  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ type:   directory

# ============================================
# PART 5: EXECUTE-ONLY DIRECTORY
# ============================================

mkdir secretdir
touch secretdir/known.txt
chmod 711 secretdir

ls secretdir
# ls: cannot open directory 'secretdir': Permission denied
# (no read = cannot list)

cat secretdir/known.txt
# (works โ€” execute allows traversal, and the name is known)

# ============================================
# PART 6: DELETION DEPENDS ON DIRECTORY
# ============================================

touch readonly.txt
chmod 444 readonly.txt
ls -l readonly.txt
# -r--r--r-- 1 alice alice 0 Mar 15 10:00 readonly.txt

rm readonly.txt
# (works โ€” the directory has write permission)

# ============================================
# PART 7: STICKY BIT ON /tmp
# ============================================

ls -ld /tmp
# drwxrwxrwt 15 root root 4096 Mar 15 10:00 /tmp
#         โ”‚
#         โ””โ”€โ”€ t = sticky bit

# ============================================
# PART 8: SETGID DIRECTORY
# ============================================

mkdir /tmp/shared
chmod 2775 /tmp/shared
ls -ld /tmp/shared
# drwxrwsr-x 2 alice developers 4096 Mar 15 10:00 /tmp/shared
#       โ”‚
#       โ””โ”€โ”€ s = setgid, files inherit "developers" group

# ============================================
# PART 9: SETUID FILE
# ============================================

ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root 68208 Mar 15 10:00 /usr/bin/passwd
#    โ”‚
#    โ””โ”€โ”€ s = setuid, runs as root even when invoked by a user

# ============================================
# PART 10: THE ORDER OF CHECKS
# ============================================

# As the owner, owner bits apply โ€” even if others would grant more
chmod 077 file.txt
ls -l file.txt
# ----rwxrwx 1 alice alice 0 Mar 15 10:00 file.txt

cat file.txt
# cat: file.txt: Permission denied
# (owner class matched, owner has no read, kernel stops)

Each part isolates one aspect of the permission model. Parts 1 through 3 show the notation. Parts 4 through 6 show the directory semantics. Parts 7 through 9 show the special bits. Part 10 shows the order-of-checks rule.


Quick Reference

Permission Values

SymbolValueMeaning (file)Meaning (directory)
r4Read contentsList entries
w2Modify contentsCreate/delete entries
x1ExecuteTraverse
-0No permissionNo permission

Common Modes

ModeSymbolicTypical Use
644rw-r--r--Regular files
600rw-------Private files, keys
755rwxr-xr-xExecutables, directories
700rwx------Private directories
777rwxrwxrwxFully open (rarely correct)
1777rwxrwxrwt/tmp (sticky)
2775rwxrwsr-xShared group directory
4755rwsr-xr-xSetuid executable

Identity Classes

ClassSymbolMatches
OwneruProcess UID = file UID
GroupgProcess GID in file’s group
OthersoNeither owner nor group

Special Bits

BitOctalOn FileOn Directory
Setuid4000Run as file owner(no effect)
Setgid2000Run as file groupNew files inherit group
Sticky1000(obsolete)Only owner can delete

chmod Notation

FormExampleEffect
Numericchmod 644 fileSet exact mode
Symbolic addchmod u+x fileAdd execute for owner
Symbolic removechmod go-w fileRemove write for group/others
Symbolic setchmod u=rw fileSet owner to exactly rw
Recursivechmod -R 755 dirApply to tree
Capital Xchmod -R a+rX dirExecute only where appropriate

File Type Characters

CharType
-Regular file
dDirectory
lSymbolic link
cCharacter device
bBlock device
sSocket
pNamed pipe

Best Practices

โœ… Do This:

# Use the least privilege that works
chmod 600 ~/.ssh/id_rsa                                        # โœ…

# Use 755 for directories and executables
chmod 755 /usr/local/bin/script.sh                             # โœ…

# Use 644 for regular readable files
chmod 644 /var/www/html/index.html                             # โœ…

# Use setgid for shared group directories
chmod 2775 /srv/project                                        # โœ…

# Use the sticky bit on world-writable directories
chmod 1777 /tmp                                                # โœ…

# Use symbolic notation for incremental changes
chmod +x script.sh                                             # โœ…

# Use -R with capital X for trees
chmod -R a+rX /var/www                                         # โœ…

โŒ Don’t Do This:

# Don't use 777 because "it works"
chmod 777 /var/www  # opens everything to everyone          # โš ๏ธ

# Don't set setuid on scripts
chmod u+s script.sh  # ignored on most systems, unsafe      # โš ๏ธ

# Don't chmod -R 777 to fix permission problems
chmod -R 777 /  # catastrophic                              # โš ๏ธ

# Don't forget the execute bit on directories
chmod 644 somedir  # cannot traverse                        # โš ๏ธ

# Don't assume read-only files cannot be deleted
rm readonly.txt  # deletion depends on the directory        # โš ๏ธ

Common Pitfalls

PitfallProblemSolution
Owner bits deny, others allowKernel stops at ownerCheck owner class first
Read-only file deletedDeletion is a directory writeCheck directory permissions
Cannot access file in r-- directoryNo traverseAdd execute: r-x
Setuid S not sExecute bit missingAdd execute
Setgid on directory not workingWrong group or missing bitVerify with ls -ld
777 “fixes” a permission problemOver-permissiveGrant the minimum
Recursive chmod changes wrong filesApplied to files and dirs alikeUse X not x
Numeric mode misunderstoodDecimal vs octal644 is octal, not decimal

Real-World Examples

1. SSH private key

chmod 600 ~/.ssh/id_rsa

2. Web directory

chmod 755 /var/www/html
chmod 644 /var/www/html/*.html

3. Script executable

chmod 755 /usr/local/bin/backup.sh

4. Shared project directory

chmod 2775 /srv/project

5. Temporary directory

chmod 1777 /tmp

6. Setuid binary

chmod 4755 /usr/local/bin/custom-tool

7. Private directory

chmod 700 ~/private

8. Incremental execute

chmod +x deploy.sh

9. Recursive with capital X

chmod -R a+rX /srv/www

10. Exact reset

chmod 644 config.ini

Visual: Permission String Anatomy

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  - r w x r - x r - -                                     โ”‚
โ”‚  โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚                                     โ”‚
โ”‚  โ”‚ โ””โ”ฌโ”˜ โ””โ”ฌโ”˜ โ””โ”ฌโ”˜                                          โ”‚
โ”‚  โ”‚  โ”‚   โ”‚   โ”‚                                            โ”‚
โ”‚  โ”‚  โ”‚   โ”‚   โ””โ”€โ”€ others:  r--  = 4                        โ”‚
โ”‚  โ”‚  โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€ group:   r-x  = 5                        โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ owner:   rwx  = 7                        โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ type:    - = regular file                โ”‚
โ”‚                                                          โ”‚
โ”‚  Numeric: 754                                            โ”‚
โ”‚                                                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: File vs Directory Meanings

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  FILE                    โ”‚  DIRECTORY                    โ”‚
โ”‚                          โ”‚                               โ”‚
โ”‚  r = read contents       โ”‚  r = list entries             โ”‚
โ”‚      (cat, less)         โ”‚      (ls)                     โ”‚
โ”‚                          โ”‚                               โ”‚
โ”‚  w = modify contents     โ”‚  w = create/delete entries    โ”‚
โ”‚      (edit, append)      โ”‚      (touch, rm, mv)          โ”‚
โ”‚                          โ”‚                               โ”‚
โ”‚  x = execute             โ”‚  x = traverse                 โ”‚
โ”‚      (./script)          โ”‚      (cd, access by name)     โ”‚
โ”‚                          โ”‚                               โ”‚
โ”‚  The same bits mean      โ”‚  The directory's w controls   โ”‚
โ”‚  different things.       โ”‚  deletion, not the file's.    โ”‚
โ”‚                                                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Order of Checks

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Process tries to open a file                            โ”‚
โ”‚       โ”‚                                                  โ”‚
โ”‚       โ–ผ                                                  โ”‚
โ”‚  Is process UID == file owner UID?                       โ”‚
โ”‚       โ”‚                                                  โ”‚
โ”‚       โ”œโ”€โ”€ Yes โ”€โ”€โ–บ Use OWNER bits. Stop.                  โ”‚
โ”‚       โ”‚                                                  โ”‚
โ”‚       โ””โ”€โ”€ No                                             โ”‚
โ”‚            โ”‚                                             โ”‚
โ”‚            โ–ผ                                             โ”‚
โ”‚  Is file's GID in process's group list?                  โ”‚
โ”‚       โ”‚                                                  โ”‚
โ”‚       โ”œโ”€โ”€ Yes โ”€โ”€โ–บ Use GROUP bits. Stop.                  โ”‚
โ”‚       โ”‚                                                  โ”‚
โ”‚       โ””โ”€โ”€ No                                             โ”‚
โ”‚            โ”‚                                             โ”‚
โ”‚            โ–ผ                                             โ”‚
โ”‚  Use OTHERS bits.                                        โ”‚
โ”‚                                                          โ”‚
โ”‚  First match wins. No fallthrough.                       โ”‚
โ”‚                                                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Traversal Requires Execute

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  /home/alice/documents/report.txt                        โ”‚
โ”‚                                                          โ”‚
โ”‚  To read report.txt, the kernel checks:                  โ”‚
โ”‚    /              โ†’ x                                    โ”‚
โ”‚    home           โ†’ x                                    โ”‚
โ”‚    alice          โ†’ x                                    โ”‚
โ”‚    documents      โ†’ x                                    โ”‚
โ”‚    report.txt     โ†’ r                                    โ”‚
โ”‚                                                          โ”‚
โ”‚  If /home/alice has mode 700, only alice can traverse.   โ”‚
โ”‚  Group and others fail at "alice" โ€” regardless of the    โ”‚
โ”‚  permissions on documents or report.txt.                 โ”‚
โ”‚                                                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Sticky Bit on /tmp

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  /tmp with mode 1777                                     โ”‚
โ”‚                                                          โ”‚
โ”‚  drwxrwxrwt                                              โ”‚
โ”‚      โ”‚  โ”‚  โ””โ”€โ”€ t = sticky                                โ”‚
โ”‚      โ”‚  โ””โ”€โ”€โ”€โ”€โ”€ w = everyone can create                   โ”‚
โ”‚      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ rwx = owner full                          โ”‚
โ”‚                                                          โ”‚
โ”‚  alice creates /tmp/alice.tmp                            โ”‚
โ”‚  bob creates /tmp/bob.tmp                                โ”‚
โ”‚                                                          โ”‚
โ”‚  alice tries: rm /tmp/bob.tmp                            โ”‚
โ”‚    โ†’ Operation not permitted                             โ”‚
โ”‚    (sticky bit: only the owner, dir owner, or root)      โ”‚
โ”‚                                                          โ”‚
โ”‚  Without the sticky bit, alice could delete bob's file.  โ”‚
โ”‚                                                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Setgid Directory

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  /srv/project with mode 2775, group "developers"         โ”‚
โ”‚                                                          โ”‚
โ”‚  drwxrwsr-x  alice developers                            โ”‚
โ”‚         โ”‚                                                โ”‚
โ”‚         โ””โ”€โ”€ s = setgid                                   โ”‚
โ”‚                                                          โ”‚
โ”‚  alice (primary group "alice") creates a file:           โ”‚
โ”‚    -rw-r--r--  alice developers  newfile.txt             โ”‚
โ”‚                    โ”‚                                     โ”‚
โ”‚                    โ””โ”€โ”€ group is "developers", NOT "alice"โ”‚
โ”‚                                                          โ”‚
โ”‚  Every file in the directory belongs to "developers",    โ”‚
โ”‚  so group permissions apply uniformly.                   โ”‚
โ”‚                                                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ConceptValue
Read4
Write2
Execute1
Owner classu
Group classg
Others classo
Setuid4000
Setgid2000
Sticky1000
Check orderOwner, group, others
Directory deleteControlled by parent’s write
Directory traverseControlled by execute

Key takeaways:

  • Linux permissions are three bits for each of three identity classes โ€” owner, group, and others โ€” checked in that order, first match wins
  • The bits mean different things for files and directories โ€” read is view vs list, write is modify vs create/delete, execute is run vs traverse
  • Deleting a file is a write operation on the parent directory, not on the file itself, so a read-only file can be deleted if the directory allows it
  • Traversing a path requires execute permission on every directory component โ€” a missing execute on any component blocks access to everything below it
  • Numeric notation sums each class’s bits โ€” read=4, write=2, execute=1 โ€” producing modes like 644, 755, and 600
  • Symbolic notation is better for incremental changes and numeric notation is better for exact modes
  • The setuid bit makes a program run as its owner โ€” this is how passwd writes to /etc/shadow without running as root
  • The setgid bit on a directory makes new files inherit the directory’s group โ€” the standard pattern for shared project directories
  • The sticky bit on a directory restricts deletion to the file owner, directory owner, or root โ€” the mechanism that keeps /tmp safe
  • The most common permission mistake is granting more than necessary โ€” 777 is almost never the right answer, and the fix for a permission problem is to find the missing bit, not to open everything

Remember: File permissions are the kernel’s answer to “who can do what.” The model is small โ€” nine bits, three classes, three types โ€” but the interaction with directories, path traversal, and the special bits produces a system that is expressive enough for everything from private keys to shared team directories. Learn to read ls -l at a glance, know the difference between file and directory meanings, and treat the special bits as tools for specific problems rather than defaults.


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!