File Permission Issues

Introduction

File permission problems are among the most common yet frustrating issues system administrators encounter. When permissions are incorrect, applications fail to read files, web servers can't serve content, databases won't start, and users can't access their data. Understanding Linux file permissions and how to diagnose and fix permission issues is fundamental to effective system administration.

This comprehensive guide provides practical approaches to diagnosing and resolving file permission problems. You'll learn to read permission notation, use diagnostic commands, identify permission-related errors, and implement proper permission schemes for web servers, applications, and multi-user environments.

File permissions control who can read, write, and execute files on Linux systems. Incorrect permissions create security vulnerabilities or prevent legitimate access. This guide teaches you to balance security with functionality using proper permission management techniques.

Understanding Linux Permissions

Permission Basics

Linux uses a three-tier permission system:

Owner (User): File creator/owner permissions Group: Group member permissions Others: Everyone else permissions

Each tier has three permission types:

Read (r/4): View file contents or list directory Write (w/2): Modify file or directory contents Execute (x/1): Run file as program or access directory

Permission Notation

# Example: -rwxr-xr--
# - = File type (- file, d directory, l link)
# rwx = Owner: read, write, execute
# r-x = Group: read, no write, execute
# r-- = Others: read only

# Numeric notation
# 7 (rwx) = 4+2+1
# 6 (rw-) = 4+2
# 5 (r-x) = 4+1
# 4 (r--) = 4

Special Permissions

SUID (4000): Execute as file owner SGID (2000): Execute as group owner, inherit group on new files Sticky Bit (1000): Only owner can delete files in directory

Initial Permission Diagnostics

Quick Permission Check

# Check specific file
ls -l /path/to/file

# Check directory and contents
ls -la /path/to/directory

# Show numeric permissions
stat -c '%a %n' /path/to/file

# Show full details
stat /path/to/file

# Find files with specific permissions
find /path -type f -perm 0777

# Check ownership
ls -l /path/to/file | awk '{print $3, $4}'

# Check your current permissions
id
groups

# Test if you can read
cat /path/to/file > /dev/null 2>&1 && echo "Can read" || echo "Cannot read"

# Test if you can write
touch /path/to/directory/.test 2>/dev/null && rm /path/to/directory/.test && echo "Can write" || echo "Cannot write"

Step 1: Common Permission Errors

Permission Denied Errors

# Error: Permission denied
# Common causes:
# 1. No read permission on file
# 2. No execute permission on directory in path
# 3. Not owner and strict permissions

# Example scenario
$ cat /var/log/private.log
cat: /var/log/private.log: Permission denied

# Check permissions
ls -l /var/log/private.log
# Output: -rw------- 1 root root 1234 Jan 11 10:00 /var/log/private.log

# Solution: Change permissions or ownership
sudo chmod 644 /var/log/private.log
# or become root
sudo cat /var/log/private.log

Cannot Create/Write Errors

# Error: cannot create regular file: Permission denied

# Check directory permissions
ls -ld /path/to/directory

# Directory needs write permission
# rwxr-xr-x = Others can't write
chmod 775 /path/to/directory

# Check directory ownership
ls -ld /path/to/directory
# Change if needed
chown user:group /path/to/directory

# Check parent directory execute permission
ls -ld /path/to
# Need x permission to access subdirectories

Cannot Execute Errors

# Error: Permission denied when running script

# Check execute permission
ls -l script.sh
# Output: -rw-r--r-- (no execute)

# Add execute permission
chmod +x script.sh
# or specifically
chmod 755 script.sh

# Verify
ls -l script.sh
# Output: -rwxr-xr-x

# Alternative: run with interpreter
bash script.sh  # Doesn't need execute permission

Step 2: Web Server Permission Issues

Apache/Nginx File Permissions

# Standard web directory permissions
# Directories: 755
# Files: 644

# Fix web directory permissions
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;

# Check web server user
ps aux | grep apache2 | head -1
ps aux | grep nginx | head -1

# Common web users
# apache, www-data, nginx, httpd

# Set ownership
chown -R www-data:www-data /var/www/html

# For upload directories
chmod 775 /var/www/html/uploads
chown -R www-data:www-data /var/www/html/uploads

# Check what user web server runs as
# Apache
grep "^User\|^Group" /etc/apache2/apache2.conf

# Nginx
grep "^user" /etc/nginx/nginx.conf

WordPress Permissions

# Standard WordPress permissions
cd /var/www/html/wordpress

# Directories
find . -type d -exec chmod 755 {} \;

# Files
find . -type f -exec chmod 644 {} \;

# wp-content permissions (for uploads)
chmod 775 wp-content
chmod 775 wp-content/uploads

# Set ownership
chown -R www-data:www-data /var/www/html/wordpress

# wp-config.php security
chmod 640 wp-config.php
chown www-data:www-data wp-config.php

# Verify
ls -la wp-config.php

Step 3: Database Permission Issues

MySQL Data Directory

# Check MySQL data directory
ls -ld /var/lib/mysql

# Should be owned by mysql user
# drwx------ mysql mysql

# Fix ownership
chown -R mysql:mysql /var/lib/mysql
chmod 700 /var/lib/mysql

# Individual database directories
chmod 700 /var/lib/mysql/database_name

# Table files
chmod 660 /var/lib/mysql/database_name/*

# MySQL socket
ls -l /var/run/mysqld/mysqld.sock
chmod 777 /var/run/mysqld/mysqld.sock
chown mysql:mysql /var/run/mysqld/mysqld.sock

PostgreSQL Permissions

# Check PostgreSQL data directory
ls -ld /var/lib/postgresql/*/main

# Should be 700 or 750
# drwx------ postgres postgres

# Fix ownership
chown -R postgres:postgres /var/lib/postgresql
chmod 700 /var/lib/postgresql/*/main

# Configuration files
chmod 640 /etc/postgresql/*/main/postgresql.conf
chown postgres:postgres /etc/postgresql/*/main/postgresql.conf

Step 4: SSH/User Permission Issues

SSH Key Permissions

# SSH is very strict about permissions

# Home directory: 755 or 700
chmod 755 /home/username
# or more secure:
chmod 700 /home/username

# .ssh directory: 700
chmod 700 /home/username/.ssh

# private keys: 600
chmod 600 /home/username/.ssh/id_rsa
chmod 600 /home/username/.ssh/id_ed25519

# public keys: 644
chmod 644 /home/username/.ssh/id_rsa.pub

# authorized_keys: 600
chmod 600 /home/username/.ssh/authorized_keys

# known_hosts: 644 or 600
chmod 644 /home/username/.ssh/known_hosts

# Ownership must be correct
chown -R username:username /home/username/.ssh

# Verify all SSH permissions
ls -la /home/username/.ssh/

# SSH won't work if permissions are wrong
# Check SSH logs for permission errors
tail -f /var/log/auth.log | grep sshd

User Home Directory Issues

# Check home directory permissions
ls -ld /home/username

# Should typically be 755
chmod 755 /home/username

# Ownership
chown username:username /home/username

# Fix all files in home directory
chown -R username:username /home/username

# Find files not owned by user
find /home/username ! -user username

# Fix specific permissions
chmod 644 /home/username/.bashrc
chmod 644 /home/username/.profile
chmod 700 /home/username/.config

Step 5: Application Permission Issues

PHP-FPM Session Directory

# Session directory permissions
ls -ld /var/lib/php/sessions

# Should be writable by php-fpm user
chmod 1733 /var/lib/php/sessions
# or
chmod 770 /var/lib/php/sessions
chown root:www-data /var/lib/php/sessions

# Check PHP-FPM user
ps aux | grep php-fpm | head -1

# Clean old sessions
find /var/lib/php/sessions -type f -mtime +7 -delete

Application Upload Directories

# Create upload directory
mkdir -p /var/www/html/uploads

# Set permissions
chmod 775 /var/www/html/uploads
chown www-data:www-data /var/www/html/uploads

# Set SGID to inherit group
chmod g+s /var/www/html/uploads

# Verify
ls -ld /var/www/html/uploads
# Should show: drwxrwsr-x www-data www-data

# New files will inherit group ownership

Log File Permissions

# Application log directory
mkdir -p /var/log/myapp
chmod 755 /var/log/myapp
chown myapp:adm /var/log/myapp

# Log files
touch /var/log/myapp/app.log
chmod 640 /var/log/myapp/app.log
chown myapp:adm /var/log/myapp/app.log

# Logrotate permissions
# Create in /etc/logrotate.d/myapp
/var/log/myapp/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0640 myapp adm
}

Step 6: Finding Permission Problems

Find Files with Wrong Permissions

# Find world-writable files (security risk)
find / -type f -perm -002 2>/dev/null

# Find world-writable directories
find / -type d -perm -002 2>/dev/null

# Find files with no owner
find / -nouser -o -nogroup 2>/dev/null

# Find SUID files
find / -perm -4000 -type f 2>/dev/null

# Find SGID files
find / -perm -2000 -type f 2>/dev/null

# Find files owned by specific user
find / -user username 2>/dev/null

# Find files modified recently
find / -type f -mtime -1 2>/dev/null

# Find executable files
find / -type f -perm -111 2>/dev/null

Permission Audit Script

cat > /tmp/permission-audit.sh << 'EOF'
#!/bin/bash

echo "Permission Security Audit"
echo "========================"

echo -e "\nWorld-writable files:"
find / -type f -perm -002 ! -path "/proc/*" ! -path "/sys/*" 2>/dev/null | head -20

echo -e "\nWorld-writable directories:"
find / -type d -perm -002 ! -path "/proc/*" ! -path "/sys/*" 2>/dev/null | head -20

echo -e "\nSUID files:"
find / -perm -4000 -type f 2>/dev/null

echo -e "\nFiles with no owner:"
find / -nouser -o -nogroup 2>/dev/null | head -20

echo -e "\nSSH permission issues:"
for user in $(ls /home); do
    if [ -d "/home/$user/.ssh" ]; then
        echo "User: $user"
        ls -la /home/$user/.ssh/ | grep -E "authorized_keys|id_rsa"
    fi
done
EOF

chmod +x /tmp/permission-audit.sh
/tmp/permission-audit.sh

Step 7: Access Control Lists (ACL)

Using ACLs for Complex Permissions

# Check if ACLs are supported
tune2fs -l /dev/sda1 | grep "Default mount options:"

# View ACLs
getfacl /path/to/file

# Set ACL for specific user
setfacl -m u:username:rw /path/to/file

# Set ACL for specific group
setfacl -m g:groupname:rwx /path/to/directory

# Set default ACL for directory (inherited by new files)
setfacl -d -m u:username:rw /path/to/directory

# Remove specific ACL
setfacl -x u:username /path/to/file

# Remove all ACLs
setfacl -b /path/to/file

# Copy ACLs
getfacl /source/file | setfacl --set-file=- /dest/file

# Recursive ACL
setfacl -R -m u:username:rwx /path/to/directory

Solutions and Best Practices

Standard Permission Schemes

# Web server directories
find /var/www -type d -exec chmod 755 {} \;
find /var/www -type f -exec chmod 644 {} \;
chown -R www-data:www-data /var/www

# User home directories
chmod 755 /home/username
chown -R username:username /home/username

# Application directories
mkdir -p /opt/myapp
chmod 755 /opt/myapp
chown -R myapp:myapp /opt/myapp

# Configuration files
chmod 640 /etc/myapp/config.conf
chown root:myapp /etc/myapp/config.conf

# Executable scripts
chmod 755 /usr/local/bin/script.sh
chown root:root /usr/local/bin/script.sh

# Log directories
chmod 755 /var/log/myapp
chown myapp:adm /var/log/myapp

Permission Reset Script

cat > /usr/local/bin/fix-web-permissions.sh << 'EOF'
#!/bin/bash

WEB_ROOT="/var/www/html"
WEB_USER="www-data"
WEB_GROUP="www-data"

echo "Fixing permissions for $WEB_ROOT"

# Set directory permissions
find "$WEB_ROOT" -type d -exec chmod 755 {} \;

# Set file permissions
find "$WEB_ROOT" -type f -exec chmod 644 {} \;

# Set ownership
chown -R $WEB_USER:$WEB_GROUP "$WEB_ROOT"

# Special directories
if [ -d "$WEB_ROOT/uploads" ]; then
    chmod 775 "$WEB_ROOT/uploads"
    chmod g+s "$WEB_ROOT/uploads"
fi

if [ -d "$WEB_ROOT/cache" ]; then
    chmod 775 "$WEB_ROOT/cache"
    chmod g+s "$WEB_ROOT/cache"
fi

echo "Permissions fixed"
ls -la "$WEB_ROOT"
EOF

chmod +x /usr/local/bin/fix-web-permissions.sh

Monitoring Permissions

cat > /usr/local/bin/monitor-permissions.sh << 'EOF'
#!/bin/bash

LOG="/var/log/permission-monitor.log"

# Check for new SUID files
CURRENT_SUID=$(find / -perm -4000 -type f 2>/dev/null | sort)
if [ -f /tmp/suid_baseline.txt ]; then
    BASELINE=$(cat /tmp/suid_baseline.txt)
    if [ "$CURRENT_SUID" != "$BASELINE" ]; then
        echo "$(date): SUID files changed!" >> "$LOG"
        diff /tmp/suid_baseline.txt <(echo "$CURRENT_SUID") >> "$LOG"
        echo "SUID files changed on $(hostname)" | mail -s "Security Alert" [email protected]
    fi
fi
echo "$CURRENT_SUID" > /tmp/suid_baseline.txt

# Check for world-writable files
WRITABLE=$(find /var/www -type f -perm -002 2>/dev/null)
if [ -n "$WRITABLE" ]; then
    echo "$(date): World-writable files found:" >> "$LOG"
    echo "$WRITABLE" >> "$LOG"
fi
EOF

chmod +x /usr/local/bin/monitor-permissions.sh
echo "0 */6 * * * /usr/local/bin/monitor-permissions.sh" | crontab -

Conclusion

File permission issues are common but manageable with proper understanding and tools. Key takeaways:

  1. Understand the basics: Owner, group, others and read, write, execute
  2. Check permissions first: Use ls -l and stat
  3. Know standard schemes: Web servers, databases, SSH all have specific requirements
  4. Balance security and functionality: Don't use 777 unless absolutely necessary
  5. Use proper ownership: Ensure files owned by correct user and group
  6. Monitor changes: Watch for unexpected permission modifications
  7. Document standards: Maintain permission schemes for your applications

Regular permission audits, proper initial configuration, and understanding these diagnostic techniques ensure secure and functional file access across your Linux systems.