| Tested on | RHEL 10.2 (Coughlan) |
|---|---|
| Package | coreutils 9.5-8.el10_2bash 5.2.26-6.el10 |
| Applies to | Ubuntu, Debian, Kali Linux, Linux Mint, Pop!_OS, Raspberry Pi OS, elementary OS, Zorin OS, Parrot OS, MX Linux, RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora, Arch Linux |
| Privilege | Normal user for most examples; sudo for chown, chgrp, and privileged paths |
| Scope | Owner, group, and other classes; read, write, and execute on files versus directories; ls -l interpretation; chmod symbolic and octal modes; chown and chgrp; recursive find patterns; brief umask, SUID, SGID, and sticky bit; permission denied diagnosis. Does not cover ACL administration, full SELinux policy, or MAC hardening. |
| Related guides | Linux command line Linux filesystem hierarchy Redirection and pipes Edit text files RHCSA tutorial |
Every path on Linux carries an owner, a group, and a mode that says which users may read, write, or execute it. The confusing part is not memorizing rwx strings—it is that the same letter means something different on a directory than on a file. This guide walks through that distinction, then shows how to change modes and ownership without reaching for chmod 777 as a default fix.
How Linux File Permissions Work
Linux classifies access into three permission classes and three operation types.
| Class | Who it applies to |
|---|---|
Owner (u) |
The user ID stored on the file |
Group (g) |
Members of the file's group ID |
Other (o) |
Everyone who is not owner and not in that group |
| Permission | On a regular file | On a directory |
|---|---|---|
Read (r) |
Open and read contents | List entry names (ls) |
Write (w) |
Change file contents | Create, rename, or delete entries (with execute) |
Execute (x) |
Run as a program or script | Traverse the directory (cd, access paths inside) |
ls -l shows the mode string, owner, and group for each path.
ls -l /etc/hosts /bin/lsSample output:
-rwxr-xr-x. 1 root root 141160 Jun 2 05:30 /bin/ls
-rw-r--r--. 1 root root 454 Aug 7 21:57 /etc/hosts/bin/ls is executable by owner, group, and other. /etc/hosts is world-readable but not executable—typical for a static text file.
Linux Permissions Quick Reference
Keep these tables nearby while you practice. They are patterns, not universal security policy.
Permission values
| Permission | Value |
|---|---|
Read (r) |
4 |
Write (w) |
2 |
Execute (x) |
1 |
Add the bits in each triplet to build octal modes. Owner, group, and other each contribute one digit.
Common modes
| Mode | Typical meaning |
|---|---|
644 |
Owner read/write; others read |
600 |
Owner read/write only |
755 |
Owner full; others read and execute |
700 |
Owner full only |
600, a public HTML file might need 644, and a shared upload directory might need a dedicated group plus sticky bit. Match the mode to the data and the users who must reach it.
Read Permission Strings from ls -l
The first ten characters describe file type and mode bits. GNU ls may add another character afterward: . commonly indicates an SELinux security context on RHEL, while + indicates additional access controls such as an ACL.
-rwxr-x---Read it from left to right:
- First character: file type (
-file,ddirectory,lsymlink) - Characters 2–4: owner
rwx - Characters 5–7: group
r-x - Characters 8–10: other
--- - Optional 11th character on GNU
ls:.for SELinux context on RHEL, or+for ACLs and similar extensions
stat prints the numeric mode when you want digits without mental arithmetic.
stat -c '%a %n' /etc/hostsSample output:
644 /etc/hosts644 maps to rw-r--r--: owner read+write (4+2), group read (4), other read (4).
Prepare the permission lab
The directory and su - student examples below use paths under /tmp/perm-lab. Run this block once on a clean VM as root before the first permission test.
Confirm a normal test account exists. On many classroom images student is already present; create it when id fails.
id studentSample output:
uid=1001(student) gid=1001(student) groups=1001(student)If the account is missing, add it:
useradd -m studentRemove any prior lab tree and create directories and sample files.
rm -rf /tmp/perm-labmkdir -p /tmp/perm-lab/{dir-r,dir-x,dir-rx,private,shared,web}echo test > /tmp/perm-lab/dir-r/testecho 'secret' > /tmp/perm-lab/private/secret.confecho 'hidden content' > /tmp/perm-lab/dir-x/hidden.txtecho 'echo hello' > /tmp/perm-lab/runme.shSet initial modes and ownership so later chmod, chown, and chgrp steps start from a known state.
chmod 755 /tmp/perm-lab/runme.sh /tmp/perm-lab/privatechmod 1777 /tmp/perm-lab/sharedchown root:root /tmp/perm-lab/private/secret.confchmod 600 /tmp/perm-lab/private/secret.confVerify the tree before you change modes in the demos.
ls -la /tmp/perm-lab/Sample output:
total 8
drwxr-xr-x. 8 root root 102 Aug 7 23:26 .
drwxrwxrwt. 29 root root 4096 Aug 7 23:26 ..
drwxr-xr-x. 2 root root 18 Aug 7 23:26 dir-r
drwxr-xr-x. 2 root root 6 Aug 7 23:26 dir-rx
drwxr-xr-x. 2 root root 24 Aug 7 23:26 dir-x
drwxr-xr-x. 2 root root 25 Aug 7 23:26 private
-rwxr-xr-x. 1 root root 11 Aug 7 23:26 runme.sh
drwxrwxrwt. 2 root root 6 Aug 7 23:26 shared
drwxr-xr-x. 2 root root 6 Aug 7 23:26 webrunme.sh starts as 755 owned by root:root. The symbolic chmod section below changes its mode; the chgrp section later sets group student.
File Permissions vs Directory Permissions
This is the section most permission guides rush past. On a file, the bits describe the file body. On a directory, they describe the directory inode—the catalog of names inside it.
For a regular file:
r— read bytes from the filew— change bytes in the filex— execute the file as a program (scripts need this too)
For a directory:
r— list names in the directory (lscan show filenames)w— add, rename, or remove entries (still needs execute on that directory)x— traverse the directory; required to reach paths inside or tocdinto it
Directory with read but no execute
Create a directory with read for everyone but no execute bit.
chmod 644 /tmp/perm-lab/dir-rls -ld /tmp/perm-lab/dir-rSample output:
drw-r--r--. 2 root root 18 Aug 7 23:17 /tmp/perm-lab/dir-rA non-root user can still list names when read is set.
su - student -c 'ls /tmp/perm-lab/dir-r'Sample output:
testOpening a file inside fails without traverse permission on the directory.
su - student -c 'cat /tmp/perm-lab/dir-r/test'Sample output:
cat: /tmp/perm-lab/dir-r/test: Permission deniedRead showed the name; execute would have allowed the kernel to resolve test inside that directory.
Directory with execute but no read
Traverse-only directories hide names from ls but still allow access when you know the full path.
chmod 711 /tmp/perm-lab/dir-xsu - student -c 'ls /tmp/perm-lab/dir-x'Sample output:
ls: cannot open directory '/tmp/perm-lab/dir-x': Permission deniedsu - student -c 'cat /tmp/perm-lab/dir-x/hidden.txt'Sample output:
hidden contentNo read bit means ls cannot enumerate entries, but execute still lets a known path work. Parent directories must also grant execute on every component of the path.
Change Permissions with chmod
chmod changes mode bits. Use symbolic form when you are toggling flags, and octal form when you are setting a complete triplet.
Symbolic mode
Symbolic syntax is who + operator + permissions:
- Who:
uowner,ggroup,oother,aall - Operator:
+add,-remove,=set exactly - Permissions:
r,w,xor combinations
Remove group write and other read on the script that still has mode 755 from the lab setup.
chmod u+x,g-w,o-r /tmp/perm-lab/runme.shls -l /tmp/perm-lab/runme.shSample output:
-rwxr-x--x. 1 root root 11 Aug 7 23:26 /tmp/perm-lab/runme.shOther users kept execute but lost read. Group is still root until the chgrp section below.
Numeric mode
Each digit is the sum of r=4, w=2, and x=1 for that class.
755 means owner 7 (4+2+1), group 5 (4+1), other 5 (4+1)—full control for the owner, read and execute for everyone else.
chmod 755 /tmp/perm-lab/dir-rxls -ld /tmp/perm-lab/dir-rxSample output:
drwxr-xr-x. 2 root root 6 Aug 7 23:16 /tmp/perm-lab/dir-rxBuild octal from what each class needs instead of copying 777 from a search result.
Change File Owner with chown
Ownership decides which user and group classes apply. Mode bits alone cannot grant access to the wrong owner.
Try reading a private file owned by root as student. The file must be root-owned with a restrictive mode for this denial to appear.
chown root:root /tmp/perm-lab/private/secret.confchmod 600 /tmp/perm-lab/private/secret.confsu - student -c 'cat /tmp/perm-lab/private/secret.conf'Sample output:
cat: /tmp/perm-lab/private/secret.conf: Permission deniedThe mode is 600, so only the owner may read. Transfer ownership when the file should belong to the application user. See the chown command for flags and edge cases; here is the everyday pattern.
chown student:student /tmp/perm-lab/private/secret.confls -l /tmp/perm-lab/private/secret.confSample output:
-rw-------. 1 student student 7 Aug 7 23:16 /tmp/perm-lab/private/secret.confsu - student -c 'cat /tmp/perm-lab/private/secret.conf'Sample output:
secretUse -R when an entire tree should change owner after a restore or deployment. By default, chown linkname changes the ownership of the file the symlink points to. Use chown -h when you specifically want to change ownership of the symbolic link itself. With -R, -H, -L, and -P control symlink traversal.
Change Group Ownership with chgrp
chgrp changes only the group field. Group members use the group triplet from ls -l.
chgrp student /tmp/perm-lab/runme.shls -l /tmp/perm-lab/runme.shSample output:
-rwxr-x--x. 1 root student 11 Aug 7 23:16 /tmp/perm-lab/runme.shThe owner is still root, but members of group student now use the middle r-x triplet. Verify the user is in that group with id; see the chgrp command for recursive trees and numeric GID forms.
Change Permissions Recursively
chmod -R 755 directory applies the same mode to every file and subdirectory. That is often wrong: directories usually need execute for traverse, while plain data files rarely need execute.
chmod -R 755 /tmp/perm-lab/webIf every file became 755, scripts and binaries might be fine, but configuration and HTML files carry unnecessary execute bits and look like a misconfiguration audit finding.
Safer pattern: directories 755, regular files 644. Add sample files if your web directory is empty.
echo 'content' > /tmp/perm-lab/web/index.htmlecho 'config' > /tmp/perm-lab/web/app.conffind /tmp/perm-lab/web -type d -exec chmod 755 {} \;find /tmp/perm-lab/web -type f -exec chmod 644 {} \;find /tmp/perm-lab/web -printf '%m %p\n'Sample output:
755 /tmp/perm-lab/web
644 /tmp/perm-lab/web/index.html
644 /tmp/perm-lab/web/app.confSee chmod recursive for more find and chmod combinations on large trees.
Understand Permissions on Newly Created Files
New files inherit bits masked by umask, and that includes files produced by a copy, which is why
cp can quietly hand you a stricter mode than the original. Our guide on how to
create, copy, move and delete files shows when to add -p or -a to
carry the source mode across. Check the current mask:
umaskSample output:
0022With umask 0022, programs commonly request mode 0666 for regular files and 0777 for directories. The kernel then clears permission bits selected by the process's umask, which commonly produces 0644 files and 0755 directories. Full examples and login-session behavior are in the dedicated umask on Linux guide—this lesson only introduces why two users with the same role can still create different default modes.
Special Permissions: SUID, SGID and Sticky Bit
Three special bits extend the basic model. They show as s or t in ls -l when active.
| Bit | Octal prefix | Typical use |
|---|---|---|
| SUID | 4 | Executable runs with owner's UID |
| SGID | 2 | Executable runs with group's GID, or new files inherit directory GID |
| Sticky | 1 | Restricts deletion/rename in shared directories to the file owner, directory owner, or a privileged process |
SUID on an executable — passwd must update /etc/shadow as root:
ls -l /usr/bin/passwdSample output:
-rwsr-xr-x. 1 root root 91424 Feb 23 05:30 /usr/bin/passwdThe s in the owner execute slot means SUID.
SGID on an executable — write runs with group tty:
ls -l /usr/bin/writeSample output:
-rwxr-sr-x. 1 root tty 24160 Jan 15 2026 /usr/bin/writeSGID on a shared directory — new files inherit the directory group when the setgid bit is on the directory (useful for project folders).
Sticky bit on a directory — world-writable paths such as /tmp use sticky so ordinary users cannot delete or rename other users' files:
ls -ld /tmp /tmp/perm-lab/sharedSample output:
drwxrwxrwt. 29 root root 4096 Aug 7 23:18 /tmp
drwxrwxrwt. 2 root root 6 Aug 7 23:16 /tmp/perm-lab/sharedThe t in other execute marks the sticky bit. This section names the bits only—hardening and auditing belong in dedicated security guides.
Diagnose Permission Denied Errors
Work through checks in order instead of widening modes blindly.
Start with the active user and group list for this shell.
id studentSample output:
uid=1001(student) gid=1001(student) groups=1001(student)Then continue:
- File mode —
ls -l pathandstat -c '%a %U %G %n' path. - Parent directories — every directory in the path needs execute for your user; a readable file in a
700directory is still unreachable. - Ownership — wrong owner after
cpas root is a common surprise. - ACLs —
+after the mode inls -l, or extra entries fromgetfacl, override basic triplets (.alone on RHEL usually marks SELinux context, not an ACL). - SELinux — when DAC looks correct but access still fails, check
ls -Zand audit logs.
Demonstrate parent directory blocking:
chmod 700 /tmp/perm-lab/privatesu - student -c 'cat /tmp/perm-lab/private/secret.conf'Sample output:
cat: /tmp/perm-lab/private/secret.conf: Permission deniedThe file mode is still 600 for student, but the directory no longer grants traverse to others.
chmod 755 /tmp/perm-lab/privateRestore traverse when you finish the test.
Understand Why Root Can Behave Differently
The superuser bypasses normal owner/group/other checks, which is why root can read a 600 file owned by another user. That does not mean every operation succeeds: SELinux may still deny a syscall, a read-only mount can block writes, and immutable or append-only attributes can block deletion or modification even for uid 0. nosuid has a different purpose—it disables setuid and setgid privilege elevation on that mount, not ordinary writes. When root sees Permission denied, look beyond chmod at MAC, mount options, and file attributes.
Common Permission Mistakes
| Symptom | Likely cause | Fix |
|---|---|---|
| Quick fix applied everywhere | chmod 777 habit |
Restore least privilege; see chmod 777 for why world-writable modes are risky |
| Scripts work, data files flagged | chmod -R 755 on a mixed tree |
Use find to set 755 on dirs and 644 on files |
| File mode looks right, still denied | Missing execute on a parent directory | namei -l path or walk ls -ld on each parent |
| App cannot write after deploy | Files owned by root from sudo cp |
chown to the service user |
| Group added but no effect | Stale shell group list | New login session or newgrp |
| DAC correct, access still fails | ACL or SELinux | getfacl, ls -Z, journal entries |
Practical Permission Examples
These lab paths mirror common production choices.
Private configuration (600 on file, traverse on parent) — only the owner reads secrets.
chmod 600 /tmp/perm-lab/private/secret.confls -l /tmp/perm-lab/private/secret.confSample output:
-rw-------. 1 student student 7 Aug 7 23:16 /tmp/perm-lab/private/secret.confExecutable script (755) — owner can edit; others may run.
chmod 755 /tmp/perm-lab/runme.shShared upload directory (1777 sticky) — anyone can create files; the sticky bit prevents ordinary users from deleting or renaming other users' entries.
ls -ld /tmp/perm-lab/sharedSample output:
drwxrwxrwt. 2 root root 6 Aug 7 23:16 /tmp/perm-lab/sharedWeb content tree (755 directories, 644 files) — visitors read static assets; execute on directories only for traversal.
find /tmp/perm-lab/web -printf '%m %p\n'Sample output:
755 /tmp/perm-lab/web
644 /tmp/perm-lab/web/index.html
644 /tmp/perm-lab/web/app.confMatch each mode to who must read, write, or traverse—not to the largest number you remember.
References
- chmod(1) — Linux man page
- chown(1) — Linux man page
- chgrp(1) — Linux man page
- GNU Coreutils — File permissions — mode structure and special bits
- path_resolution(7) — how paths traverse directories
Summary
You mapped every path to an owner, a group, and three permission classes, then learned that r, w, and x mean different things on files versus directories. Listing a directory requires read; reaching a file inside requires execute on the directory and on each parent in the path. That distinction explains many “I can see the file in ls but cat fails” reports.
chmod sets those bits symbolically or in octal; chown and chgrp decide which user and group triplets apply. Recursive chmod -R 755 is a common mistake—use find to give directories execute without marking every document executable. New objects inherit umask, and SUID, SGID, and sticky bits cover the exceptions you still see in /usr/bin/passwd and /tmp.
When Permission denied appears, walk identity, mode, parents, ownership, ACLs, and SELinux before reaching for world-writable modes. The RHCSA tutorial syllabus continues with deeper ownership and security topics; ACL and SELinux administration stay in their own guides rather than on this page.

