RED HAT ENTERPRISE LINUX
File Permission
Problems
Diagnose and correct file permission problems
CIS126RH | RHEL System Administration 1
Mesa Community College
Permission denied errors are among the most common problems an administrator
encounters. Understanding how Linux evaluates permission — checking ownership,
group membership, and the nine permission bits in sequence — allows precise
diagnosis. Knowing chmod, chown, chgrp,
special bits, and the umask allows precise correction.
This module covers the complete permission model and diagnostic workflow.
These skills appear throughout the RHCSA exam.
Learning Objectives
- Read and interpret permission output from ls -l — Decode the permission string, owner, group, and file type from the long listing format
- Understand how Linux evaluates permissions — Explain the owner → group → other evaluation order and why it matters for diagnosis
-
Change permissions with chmod —
Use both symbolic (
u+x) and octal (755) notation to set file and directory permissions -
Change ownership and apply special bits —
Use
chownandchgrpto change ownership, and apply setuid, setgid, and sticky bit as needed
Reading ls -l Output
The long listing format shows every piece of information needed to diagnose a permission problem.
$ ls -l /var/www/html/
total 16
drwxr-xr-x. 2 root root 4096 May 25 10:00 images
-rw-r--r--. 1 root root 512 May 25 10:00 index.html
-rwxr-x---. 1 apache www 89 May 25 10:00 cgi-bin/app.sh
-rw-rw-r--. 1 alice dev 1024 May 25 10:00 draft.html
# Anatomy of one line:
- rw- r-- r--. 1 root root 512 May 25 10:00 index.html
# ^ ^ ^ ^ ^ ^ ^
# | | | | | | group
# | | | | | owner
# | | | | hard link count
# | | | other permissions
# | | group permissions
# | owner permissions
# file type: - file, d directory, l symlink, b block, c char
The . after the permission string means the file has an SELinux security
context. A + means ACLs are set. Neither affects standard permission
evaluation — but they are important for SELinux and ACL diagnostics.
How Linux Evaluates Permissions
Linux checks permissions in a strict sequence. The first match applies — no further checks are made.
-
Is the user the file owner?
If yes → apply owner permissions (first three bits) — done -
Is the user a member of the file's group?
If yes → apply group permissions (middle three bits) — done - Otherwise → apply other permissions (last three bits)
The root user is never denied access by standard file permissions. root can read, write, and execute any file regardless of the permission bits. SELinux is the layer that restricts root — standard permissions do not.
If a file is ----rwxrwx and owned by alice, and alice tries to access
it — she is denied! Linux sees she is the owner, applies the owner bits (---), and
stops. It never looks at the group or other bits for alice.
Permission Bits: Files vs Directories
The same three bits — read, write, execute — mean different things depending on whether they are applied to a file or a directory.
| Bit | On a regular file | On a directory |
|---|---|---|
r (read, 4) |
Read the file contents (cat, less) |
List the directory contents (ls) |
w (write, 2) |
Modify or truncate the file | Create, delete, or rename files within the directory |
x (execute, 1) |
Run the file as a program | Enter the directory (cd) and access files within it |
A directory with r but not x allows listing filenames
but not accessing them. A directory with x but not r
allows accessing files by name but not listing them. Both rx together
are needed for normal directory access.
chmod: Symbolic Notation
Symbolic notation is readable and precise for making targeted changes to specific permission bits without affecting others.
# Syntax: chmod [ugoa][+/-/=][rwxst] FILE
# Add execute for the file owner
$ chmod u+x script.sh
# Remove write from group and other
$ chmod go-w config.conf
# Set group to read-only (replace, not add)
$ chmod g=r report.txt
# Add read and execute for all (u, g, o)
$ chmod a+rx /opt/shared/
# Remove execute from owner only
$ chmod u-x norun.sh
# Multiple changes in one command
$ chmod u+x,g-w,o=r file.txt
# Apply recursively to a directory tree
$ sudo chmod -R g+rX /var/www/html/
# Capital X = execute only if already executable or a directory
chmod: Octal Notation
Octal notation sets all nine permission bits at once with a three-digit number. Each digit is the sum of the active bits for that category.
# Bit values: r=4, w=2, x=1
# Digit = sum of active bits for owner | group | other
# 755 = rwxr-xr-x (owner: 4+2+1=7, group: 4+0+1=5, other: 4+0+1=5)
$ chmod 755 script.sh
# 644 = rw-r--r-- (owner: 4+2=6, group: 4, other: 4)
$ chmod 644 index.html
# 600 = rw------- (owner: 6, group: 0, other: 0)
$ chmod 600 ~/.ssh/id_rsa
# 700 = rwx------ (owner has all, nobody else)
$ chmod 700 ~/.ssh/
# 664 = rw-rw-r-- (owner and group can write)
$ chmod 664 shared.txt
# 000 = --------- (no permissions for anyone)
$ chmod 000 locked.txt
| Octal | Symbolic | Common use |
|---|---|---|
755 | rwxr-xr-x | Executable files, directories |
644 | rw-r--r-- | Regular files (web content, configs) |
600 | rw------- | Private key files, sensitive configs |
700 | rwx------ | Private directories (~/.ssh) |
664 | rw-rw-r-- | Group-editable shared files |
640 | rw-r----- | Config files readable by group only |
Changing Ownership: chown and chgrp
Ownership determines which set of permission bits applies to a user. Only root can change file ownership.
# Change owner only
$ sudo chown alice report.txt
# Change owner and group simultaneously
$ sudo chown alice:developers report.txt
# Change group only (using chown with colon notation)
$ sudo chown :developers report.txt
# Change group only (using chgrp)
$ sudo chgrp developers report.txt
# Change ownership recursively
$ sudo chown -R apache:apache /var/www/html/
# Verify ownership change
$ ls -l report.txt
-rw-r--r--. 1 alice developers 1024 May 25 10:00 report.txt
Both colon and dot separate user from group in chown:
chown alice:developers and chown alice.developers
are equivalent. Colon is the modern preferred form.
Special Permission Bits
Three additional bits extend the permission system beyond basic read/write/execute.
| Bit | Octal | On executable files | On directories |
|---|---|---|---|
| setuid (SUID) | 4000 |
Process runs as the file's owner, not the caller (passwd, sudo) |
No standard effect on Linux |
| setgid (SGID) | 2000 |
Process runs with the file's group, not the caller's group | New files inherit the directory's group, not the creator's primary group |
| Sticky bit | 1000 |
Historically prevented swapping — no modern effect on files | Only the file owner, directory owner, or root can delete files in the directory (/tmp) |
# Set setuid on a file (shown as 's' in owner execute position)
$ sudo chmod 4755 /usr/bin/myapp # or: chmod u+s
# Set setgid on a directory (shown as 's' in group execute position)
$ sudo chmod 2775 /opt/shared/ # or: chmod g+s
# Set sticky bit on a directory (shown as 't' in other execute position)
$ sudo chmod 1777 /tmp/public/ # or: chmod +t
The umask: Default Permission Mask
The umask defines which permissions are removed from newly
created files and directories. It subtracts permissions from the maximum possible.
# View the current umask
$ umask
0022
# How umask works:
# Max permissions: file=666 (rw-rw-rw-) directory=777 (rwxrwxrwx)
# umask 022: remove --w--w- from files, --w--w- from directories
# Result: file=644 (rw-r--r--) directory=755 (rwxr-xr-x)
# Set umask for the current shell session
$ umask 027 # files=640, directories=750
$ umask 002 # files=664, directories=775 (group-write allowed)
# Set umask persistently in user's shell config
$ echo "umask 027" >> ~/.bashrc
# Set system-wide default umask
$ sudo vim /etc/profile.d/umask.sh
umask 022
New files are created with 644 (666 - 022). New directories are created with 755 (777 - 022). The leading zero is the special bits mask — normally zero.
Diagnosing Permission Problems
A "Permission denied" error is caused by one of a small number of root causes. A systematic check identifies which one applies.
-
Identify the acting user and what they are trying to do
id— show current user, UID, and group memberships -
Check the file's permissions and ownership
ls -l FILE— read type, permission string, owner, group -
Check all parent directories for execute permission
ls -ld /path /path/to /path/to/file -
Apply the evaluation model
Is the user the owner? Is the user in the file's group? What do the applicable bits allow? -
Check SELinux if standard permissions look correct
ls -Z FILEandausearch -m avc -ts recent
Common Permission Problem Patterns
| Symptom | Likely cause | Diagnostic command | Fix |
|---|---|---|---|
| User cannot read a file they should access | Wrong group, or other has no read | ls -l FILE, id USER |
chmod o+r FILE or add user to group |
| User cannot enter a directory | Directory missing execute bit | ls -ld DIR |
chmod u+x DIR or chmod 755 DIR |
| Web server cannot serve files | Files not readable by apache/nginx | ls -la /var/www/html/, id apache |
chmod -R 644 files; chmod -R 755 dirs |
| Script runs but produces "Permission denied" | Script lacks execute bit | ls -l script.sh |
chmod +x script.sh |
| User can list files but cannot open them | Directory has r but not x | ls -ld DIR |
chmod +x DIR |
| Shared directory: new files not accessible to group | setgid not set on directory | ls -ld DIR (no s in group pos) |
chmod g+s DIR |
Practical Diagnosis Example
The apache web server cannot serve /var/www/html/index.html.
Diagnose and fix the problem step by step.
# Step 1: Check what user apache runs as
$ id apache
uid=48(apache) gid=48(apache) groups=48(apache)
# Step 2: Check file permissions
$ ls -l /var/www/html/index.html
-rw-------. 1 root root 512 May 25 10:00 index.html
# ^^^ only root can read — apache cannot
# Step 3: Check parent directory permissions
$ ls -ld /var/www/html/
drwxr-xr-x. 2 root root 4096 May 25 10:00 /var/www/html/
# ^^^^^^^ apache can enter (has r-x as "other") — dir OK
# Diagnosis: file is 600 — only owner (root) can read it
# apache is "other" — gets --- from the 600 permission
# Fix: make file world-readable
$ sudo chmod 644 /var/www/html/index.html
# Verify
$ ls -l /var/www/html/index.html
-rw-r--r--. 1 root root 512 May 25 10:00 index.html
# ^^^^^^^ apache (other) now has r-- — can read
Setting Up a Collaborative Directory
A common exam task: create a directory where all members of a group can read and write files, and new files inherit the group automatically.
# Scenario: /opt/team should be readable/writable by the 'devs' group
# Step 1: Create the group and add users
$ sudo groupadd devs
$ sudo usermod -aG devs alice
$ sudo usermod -aG devs bob
# Step 2: Create directory with group ownership
$ sudo mkdir /opt/team
$ sudo chown root:devs /opt/team
# Step 3: Set permissions — rwxrwsr-x (setgid = 2775)
$ sudo chmod 2775 /opt/team
# Verify
$ ls -ld /opt/team
drwxrwsr-x. 2 root devs 4096 May 25 10:00 /opt/team
# ^ s in group execute = setgid is set
# Test: alice creates a file — it gets group 'devs' automatically
$ su - alice -c "touch /opt/team/myfile.txt"
$ ls -l /opt/team/myfile.txt
-rw-rw-r--. 1 alice devs 0 May 25 10:00 myfile.txt
# ^^^^ group is devs, not alice's primary group
Permission Management Quick Reference
| Task | Command |
|---|---|
| View permissions (long format) | ls -l FILE |
| View directory permissions | ls -ld DIR |
| View current user and groups | id |
| Set permissions (octal) | chmod 644 FILE |
| Add execute for owner | chmod u+x FILE |
| Remove write from group and other | chmod go-w FILE |
| Recursive permission change | chmod -R 755 DIR |
| Change file owner | sudo chown USER FILE |
| Change owner and group | sudo chown USER:GROUP FILE |
| Change group only | sudo chgrp GROUP FILE |
| Set setuid | chmod u+s FILE or chmod 4755 FILE |
| Set setgid on directory | chmod g+s DIR or chmod 2775 DIR |
| Set sticky bit on directory | chmod +t DIR or chmod 1777 DIR |
| View and change umask | umask / umask 027 |
Common Mistakes
| Mistake | What goes wrong | Correct approach |
|---|---|---|
| Forgetting to check parent directory permissions | File permissions look correct but access is still denied | Use ls -ld /path /path/to /path/to/file to check entire path |
Using chmod -R 777 to fix a permission problem |
Secures the symptom but creates a severe security risk | Diagnose the actual cause and apply the minimum required permissions |
| Confusing owner-check-first with "most permissive wins" | File owner cannot access a file that group members can (e.g. ----rwxrwx) |
Remember: owner bits are checked first and only — group/other are never checked for the owner |
| Not using setgid on a shared directory | New files get the creator's primary group — other group members cannot access them | Apply chmod g+s DIR to make new files inherit the directory's group |
| Setting execute on a regular data file | Security risk — file could potentially be executed; also confusing in listings | Execute is for programs and scripts only — data files should not have execute |
Using chmod -R with same mode for files and directories |
chmod -R 755 makes all files executable; most data files should not be |
Use capital X: chmod -R u=rwX,go=rX DIR — sets execute on directories only |
Knowledge Check
Answer these before moving to the next slide.
- A file has permissions
-rw-r-----owned byalice:sales. Can bob (who is in thesalesgroup) read the file? Can carol (not in any relevant group) read it? - Write the
chmodcommand (octal) to set a file to be readable and writable by the owner, readable by group, and not accessible by others. - A user runs
ls /data/reports/and sees the filenames, but when they trycat /data/reports/q1.txtthey get "Permission denied". What is the likely permission configuration, and what is the fix? - Write the three commands to set up
/opt/sharedso that all members of thestaffgroup can read and write files, and new files automatically inherit thestaffgroup. - What is the current umask if newly created files have permissions
640and new directories have permissions750? - What do the setuid, setgid, and sticky bits do, and where is each commonly used?
Knowledge Check — Answers
- Bob is in the
salesgroup — Linux applies the group bits (r--) — yes, bob can read. Carol is neither the owner nor in sales — Linux applies other bits (---) — carol cannot read. chmod 640 FILE— owner: 4+2=6 (rw-), group: 4 (r--), other: 0 (---).- The directory has
rbut notxfor the user — they can see the names (r) but cannot access the files (no x). Fix:chmod +x /data/reports/orchmod 755 /data/reports/to grant execute permission. - (1)
sudo chown :staff /opt/shared— set group ownership
(2)sudo chmod 2775 /opt/shared— rwxrwsr-x (setgid + group write)
(3) Verify:ls -ld /opt/shared— should showsin group execute position - umask
027— files: 666 − 027 = 640; directories: 777 − 027 = 750. The umask subtracts its bits from the maximum permissions. - setuid: process runs as the file owner — used on executables
like
passwdthat need elevated privilege. setgid: on files — process runs with file's group; on directories — new files inherit the directory's group (shared workspace directories). Sticky bit: on directories — only the file owner, directory owner, or root can delete files (used on/tmpto prevent users deleting each other's files).
Key Takeaways
- Linux evaluates permissions in order: owner → group → other. First match wins. The owner's bits always apply to the owner — even if group or other has more access. Check the full path: a file with 644 is inaccessible if its parent directory lacks execute permission.
-
Use
ls -lto read,chmodto set permissions. Octal (644, 755, 700) sets all nine bits at once. Symbolic (u+x, go-w) makes targeted changes. Use capitalXwith-Rto set execute on directories only. -
Use
chown USER:GROUPto fix ownership issues. Only root can change ownership. The right ownership combined with the right permissions eliminates most access problems. For shared directories, combinechown :GROUPwithchmod 2775(setgid) so new files inherit the group. -
The umask subtracts from default permissions for new files and directories.
Default umask 022 → new files 644, new directories 755.
umask 027 → new files 640, new directories 750.
Set persistent umask in
~/.bashrcor/etc/profile.d/.
Graded Lab
- Create three files:
public.txt(644),private.txt(600), andgroup.txt(660). Verify withls -l. Log in as a second user and confirm which files are accessible and which are not. - Create a directory
/tmp/testdirwith permissions 444 (read-only for all). Attempt to enter it withcd. Observe the error. Fix withchmod +xand confirm you can now enter. - Create a group
labteam. Create/opt/labshareowned byroot:labteamwith permissions 2775. Add two lab users to the group. As each user, create a file and verify it gets grouplabteamautomatically. - Check the current umask. Change it to 027. Create a new file and directory. Verify the new file has 640 and the directory has 750. Reset the umask to 022.
- Break a permission intentionally: set
/etc/hostspermissions to 000 (as a copy in /tmp). Then usels -lto diagnose, andchmodto restore 644. Verifycatworks again. - Diagnose this scenario: a file
/data/report.txtis owned byroot:rootwith permissions 640. A user in no relevant group reports they cannot read it. Determine the correct fix and apply it.
"Diagnose and correct file permission problems."
Read with ls -l. Evaluate using owner→group→other. Fix with
chmod and chown. Check parent directories. Check SELinux last.