Mastering File Permissions: Practical Control with chmod
Setting correct file and directory permissions is critical for any Unix-like system. Missteps—like defaulting to chmod 777
—invite unauthorized access and operational disasters. Granular control via chmod
ensures that only the right users have the right access: nothing more, nothing less.
Anatomy of Permissions
Every file and directory is defined by three user classes:
- User (
u
): file owner - Group (
g
): members of the file’s group - Other (
o
): everyone else
And each class receives three possible actions:
- Read (
r
): view file contents/list directory - Write (
w
): modify contents or (for directories) add/remove items - Execute (
x
): run file or traverse directory
Sample permission string:
drwxr-x---
| | | |
| | | +-- other: none
| | +---- group: read, execute
| +------ user: read, write, execute
+--------- “d” = directory, “-” = regular file
On a freshly installed Ubuntu 22.04 LTS system, the default /etc/passwd
is typically -rw-r--r-- (644)
—note how only root gets write access.
chmod
Syntax: Symbolic vs Numeric
Two syntax forms exist: symbolic (recommended for incremental tweaks) and numeric (preferred for batch/CI, and exact control).
Symbolic Mode
Modify permissions with operations:
chmod [ugoa][+-=][rwx] <file>
+
: add permission-
: remove=
: set exactly
Example: Make a script executable only by its group:
chmod g+x,go-w backup.sh
Useful for: post-install adjustments, scripts with evolving requirements.
Numeric (Octal) Mode
Express permissions by summing read (4), write (2), and execute (1):
user | group | other | |
---|---|---|---|
7 | rwx | ||
5 | r-x | ||
0 | --- |
So,
chmod 750 deploy.sh
means: owner=all, group=read/execute, others=none.
Note: Be explicit. Passing chmod 755
to a directory tree can inadvertently expose sensitive scripts unless you narrow the glob.
Common chmod
Scenarios
1. Tightening World-Write Permissions
Accidentally inherited a drwxrwxrwx
directory from a mounted NTFS volume? Strip dangerous permissions in a single sweep:
chmod -R o-w,g-w /mnt/extra
Check with:
find /mnt/extra -perm /o+w
# returns nothing if world-writable bits are gone
2. Script Execution Restrictions
Deploying system scripts in /usr/local/bin
? It’s tempting to chmod 755 *
, but consider:
- Only scripts needing public execution should be world-executable.
- For critical tooling:
Onlychmod 750 /usr/local/bin/db-migrate chown root:devops /usr/local/bin/db-migrate
root
and members of thedevops
group can run this migration.
3. Handling Directories vs Files
Directories require execute (x
) for traversal, not just listing. Debug frustrating Permission denied
errors when users can’t cd
into a folder but can see its contents with ls
.
Real-world gotcha:
chmod 700 /srv/secure-dir
chmod 644 /srv/secure-dir/file.txt
# Group can read the file itself—but can't enter the directory to get to it.
4. Reset Default Creation Behavior: umask
To prevent overexposed defaults, set your umask
in /etc/profile
or session:
umask 027
Future files: owner can read/write, group can read, others nothing. This won’t retroactively fix existing files—use find
in combo with chmod
for remediation.
Advanced: Sticky Bits, SetUID, and SetGID
Flags that often surface in team environments or software deployment:
- SetUID (
u+s
): run as the file owner, not the executor (chmod u+s
). - SetGID (
g+s
): files created in the directory inherit group; crucial for shared project folders. - Sticky Bit (
+t
): only file owners/root can delete from world-writable public folders (/tmp
classic example).
Example—restrict /var/www/uploads
to allow group collaboration, prevent accidental deletes:
chmod 2770 /var/www/uploads
chown :webteam /var/www/uploads
Now, new files inherit webteam
group, accessible only to group, with no external exposure.
Real-World Permissions Debugging
Permissions mismatches often result in ambiguous errors. Apache refusing to serve static assets?
[error] (13)Permission denied: access to '/var/www/html/logo.png' denied
Check both:
- file permissions:
chmod 644 logo.png
- directory chain: every parent directory must be at least executable for the web server user
Not-so-obvious Tip
When troubleshooting, combine ls -l
and namei -l <path>
to reveal permission flow along a path. It quickly surfaces unexpected blockers.
Summary
chmod
is deceptively simple—yet underpins the security posture and usability of any Linux/Unix deployment. Use symbolic mode for clarity, numeric for predictability. Always verify the effective permission path, and prefer minimum required privileges.
No blanket rules—context and principle of least privilege always win out.
Questions, weird chmod
puzzles, or legacy system quirks? Start a discussion below.