Linux File Permissions Deep Dive: chmod, chown, and ACLs
Understanding Linux file permissions with chmod, chown, and Access Control Lists (ACLs) for fine-grained access control.
Introduction
Linux file permissions control who can read, write, and execute files. While basic permissions (owner/group/others) cover most use cases, complex environments often require finer-grained control. Access Control Lists (ACLs) provide this additional granularity. This post covers permission management from basic to advanced.
Environment
The examples use Ubuntu 22.04 LTS with a shared project directory that multiple users and services need to access with different permission levels.
ls -la /shared/
# total 0
# drwxr-xr-x 2 root root 4096 Mar 1 10:00 .
# drwxr-xr-x 3 root root 4096 Mar 1 10:00 ..
# -rw-r--r-- 1 root root 0 Mar 1 10:00 config.ymlProblem
Multiple users need different access levels to the same directory:
- Developers need full read/write access
- Deployers need read/write to specific files
- The monitoring service needs read-only access to logs
- Nobody else should have access
Basic permissions (owner/group/others) cannot accommodate this complexity.
Analysis
Linux permissions consist of three sets of three bits:
rwxrwxrwx
||| ||| |||
||| ||| other: everyone else
||| group: users in the file's group
owner: the file's ownerNumbers represent permissions:
- 4 = read (r)
- 2 = write (w)
- 1 = execute (x)
Common combinations:
- 755 = rwxr-xr-x (directories)
- 644 = rw-r--r-- (regular files)
- 700 = rwx------ (private directories)
- 600 = rw------- (private files)
Solution
1. Change permissions with chmod
# Symbolic mode
chmod u+x script.sh # Add execute for owner
chmod g+w file.txt # Add write for group
chmod o-rwx secret.txt # Remove all permissions for others
# Numeric mode
chmod 755 directory/
chmod 644 file.txt
chmod 700 private/2. Change ownership with chown
# Change owner
sudo chown deploy:deploy /opt/myapp
# Change recursively
sudo chown -R www-data:www-data /var/www/html
# Change only owner
sudo chown deploy /opt/myapp
# Change only group
sudo chgrp developers /shared/code3. Use ACLs for fine-grained control
# Check if ACLs are enabled
mount | grep acl
# /dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro)
# Install ACL tools
sudo apt-get install acl
# Set ACL for a user
setfacl -m u:deploy:rwx /shared/config.yml
# Set ACL for a group
setfacl -m g:developers:rw /shared/code/
# Set default ACL for new files
setfacl -d -m g:developers:rw /shared/code/
# View ACLs
getfacl /shared/config.yml
# # file: shared/config.yml
# # owner: root
# # group: root
# user::rw-
# user:deploy:rwx
# group::r--
# mask::rwx
# other::r--4. Use setuid and setgid
# Set setuid (runs as file owner)
sudo chmod u+s /usr/bin/passwd
# -rwsr-xr-x 1 root root /usr/bin/passwd
# Set setgid (runs as file group)
chmod g+s /shared/code/
# drwxrwsr-x 2 root developers /shared/code/5. Use the sticky bit
# Prevent users from deleting others' files
chmod +t /tmp/
# drwxrwxrwt 10 root root 4096 /tmp/6. Check permissions recursively
# Find files with specific permissions
find /shared -perm 777
# Find files not owned by expected user
find /opt/myapp ! -user deploy
# Find world-writable files
find / -xdev -type f -perm -00027. Set permissions for web servers
# Nginx/Apache
sudo chown -R www-data:www-data /var/www/html
sudo find /var/www/html -type d -exec chmod 755 {} \;
sudo find /var/www/html -type f -exec chmod 644 {} \;
# Upload directory needs write access
sudo chmod 775 /var/www/html/uploads
sudo setfacl -m g:www-data:rwx /var/www/html/uploads8. Use umask for default permissions
# Check current umask
umask
# 0022
# Set umask for more restrictive defaults
umask 027
# New files: 640
# New directories: 750
# Set permanently in ~/.bashrc
echo "umask 027" >> ~/.bashrc9. Copy permissions from another file
# Copy permissions
chmod --reference=reference_file target_file
# Copy ownership
sudo chown --reference=reference_file target_file10. Remove ACL entries
# Remove specific ACL entry
setfacl -x u:deploy /shared/config.yml
# Remove all ACLs
setfacl -b /shared/config.yml11. Audit permission changes
# Log permission changes with auditd
sudo auditctl -w /shared -p wa -k shared_perm
# Search audit logs
sudo ausearch -k shared_permLessons Learned
Basic permissions cover most use cases, but ACLs are essential for complex multi-user environments. Always use the principle of least privilege. Set appropriate umask values for new files. And regularly audit permissions with find and auditd to catch misconfigurations before they become security issues.
This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.