Linux File Permissions & Access Control

Linux file permissions are a fundamental security mechanism that controls who can read, write, and execute files and directories. This lesson covers standard Unix permissions, special permissions, Access Control Lists (ACLs), and practical security implementations.

Linux File Permissions & Access Control

Overview

Linux file permissions are a fundamental security mechanism that controls who can read, write, and execute files and directories. This lesson covers standard Unix permissions, special permissions, Access Control Lists (ACLs), and practical security implementations.

Learning Objectives

  • Master the Linux permission model (rwx)
  • Understand user, group, and other permissions
  • Configure special permissions (SUID, SGID, Sticky Bit)
  • Implement Access Control Lists (ACLs)
  • Apply security best practices
  • Troubleshoot permission-related issues

Prerequisites

  • Basic Linux command line knowledge
  • Understanding of users and groups
  • Access to a Linux system or WSL
  • Basic file system navigation skills

Core Concepts

The Linux Security Model

Linux uses a discretionary access control (DAC) model where file owners control access permissions for their files.

Permission Components

1. **Owner (User)**: The user who owns the file 2. **Group**: The group associated with the file 3. **Others**: Everyone else on the system 4. **Root**: Superuser with unlimited access

Permission Types

  • **Read (r)**: View file contents or list directory
  • **Write (w)**: Modify file or add/remove files in directory
  • **Execute (x)**: Run file as program or access directory

Understanding Permission Notation

Symbolic Notation (rwxrwxrwx)

ls -l /home/user/file.txt
-rw-r--r-- 1 user group 1024 Dec 1 10:00 file.txt

# Breaking down: -rw-r--r--
# - : File type (- = regular file, d = directory, l = link)
# rw- : Owner permissions (read, write, no execute)
# r-- : Group permissions (read only)
# r-- : Others permissions (read only)

Numeric (Octal) Notation

# Each permission has a numeric value:
# Read (r) = 4
# Write (w) = 2
# Execute (x) = 1

# Examples:
# 755 = rwxr-xr-x (common for executables)
# 644 = rw-r--r-- (common for files)
# 600 = rw------- (private files)
# 777 = rwxrwxrwx (avoid - security risk!)

Permission Calculation Table

| Permission | Binary | Octal | Meaning | |------------|--------|-------|---------| | --- | 000 | 0 | No permissions | | --x | 001 | 1 | Execute only | | -w- | 010 | 2 | Write only | | -wx | 011 | 3 | Write and execute | | r-- | 100 | 4 | Read only | | r-x | 101 | 5 | Read and execute | | rw- | 110 | 6 | Read and write | | rwx | 111 | 7 | Full permissions |

Basic Permission Management

Viewing Permissions

# Long format listing
ls -l filename

# Show hidden files too
ls -la

# Directory permissions
ls -ld /directory

# Detailed file information
stat filename

# Check your user and groups
id
whoami
groups

Changing Permissions with chmod

Symbolic Method

# Add permission
chmod u+x file.sh          # Add execute for owner
chmod g+w file.txt         # Add write for group
chmod o-r file.conf        # Remove read for others
chmod a+r file.txt         # Add read for all (a = all)

# Set exact permissions
chmod u=rwx,g=rx,o=r file # Owner: rwx, Group: r-x, Others: r--

# Multiple changes
chmod u+x,g+w,o-r file     # Multiple operations

# Recursive changes
chmod -R u+w directory/    # Apply to all files in directory

Numeric Method

# Set exact permissions
chmod 755 script.sh        # rwxr-xr-x
chmod 644 document.txt     # rw-r--r--
chmod 600 private.key      # rw-------
chmod 700 private_dir/     # rwx------

# Recursive
chmod -R 755 /var/www/html # Web server files
chmod -R 600 ~/.ssh/       # SSH keys (except public keys)

Changing Ownership with chown

# Change owner
chown newuser file.txt

# Change owner and group
chown newuser:newgroup file.txt

# Change group only
chown :newgroup file.txt
# or use chgrp
chgrp newgroup file.txt

# Recursive ownership change
chown -R webuser:www-data /var/www/html

# Copy ownership from another file
chown --reference=template.txt target.txt

Directory Permissions

Directory Permission Meanings

  • **Read (r)**: List directory contents (ls)
  • **Write (w)**: Create, delete, rename files in directory
  • **Execute (x)**: Access directory and its contents (cd)

Common Directory Permissions

# Public directory (everyone can access)
chmod 755 public_dir/      # drwxr-xr-x

# Shared directory (group collaboration)
chmod 770 shared_dir/      # drwxrwx---
chmod g+s shared_dir/      # Set SGID for group inheritance

# Private directory
chmod 700 private_dir/     # drwx------

# Drop box (users can add but not see files)
chmod 733 dropbox/         # drwx-wx-wx

Special Permissions

SUID (Set User ID) - 4000

When set on executable, runs with owner's privileges

# Set SUID
chmod u+s program          # Symbolic
chmod 4755 program         # Numeric (4xxx)

# Example: passwd command
ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 Feb 6 2024 /usr/bin/passwd

# Find all SUID files (security audit)
find / -perm -4000 -type f 2>/dev/null

SGID (Set Group ID) - 2000

  • On executable: Runs with group's privileges
  • On directory: New files inherit directory's group
# Set SGID
chmod g+s directory/       # Symbolic
chmod 2755 directory/      # Numeric (2xxx)

# Example: Shared project directory
mkdir /projects/team1
chgrp developers /projects/team1
chmod 2770 /projects/team1
# Now all files created inherit 'developers' group

# Find all SGID files/directories
find / -perm -2000 2>/dev/null

Sticky Bit - 1000

Prevents users from deleting files they don't own in shared directories

# Set sticky bit
chmod +t directory/        # Symbolic
chmod 1777 directory/      # Numeric (1xxx)

# Example: /tmp directory
ls -ld /tmp
drwxrwxrwt 23 root root 4096 Dec 1 10:00 /tmp

# Find directories with sticky bit
find / -perm -1000 -type d 2>/dev/null

Combining Special Permissions

# SUID + SGID
chmod 6755 program         # rwsr-sr-x

# SGID + Sticky
chmod 3770 shared_dir/     # rwxrws--T

# All special permissions
chmod 7777 special_file    # rwsrwsrwt (never do this!)

Default Permissions and umask

Understanding umask

umask sets default permissions for new files and directories

# View current umask
umask           # Octal format
umask -S        # Symbolic format

# How umask works:
# File default: 666 (rw-rw-rw-)
# Directory default: 777 (rwxrwxrwx)
# Subtract umask value

# Example with umask 022:
# File: 666 - 022 = 644 (rw-r--r--)
# Directory: 777 - 022 = 755 (rwxr-xr-x)

Setting umask

# Temporary change (current session)
umask 077       # Very restrictive (files: 600, dirs: 700)
umask 022       # Common default (files: 644, dirs: 755)
umask 002       # Group-friendly (files: 664, dirs: 775)

# Permanent change
echo "umask 022" >> ~/.bashrc
# System-wide
echo "umask 022" >> /etc/profile

Common umask Values

| umask | File Result | Directory Result | Use Case | |-------|-------------|------------------|----------| | 000 | 666 (rw-rw-rw-) | 777 (rwxrwxrwx) | Never use! | | 002 | 664 (rw-rw-r--) | 775 (rwxrwxr-x) | Group collaboration | | 022 | 644 (rw-r--r--) | 755 (rwxr-xr-x) | Default for most systems | | 027 | 640 (rw-r-----) | 750 (rwxr-x---) | Secure, group readable | | 077 | 600 (rw-------) | 700 (rwx------) | Private files only |

Access Control Lists (ACLs)

Extended Permissions Beyond Traditional Unix

ACLs provide fine-grained access control for specific users and groups

Viewing ACLs

# Check if file has ACL (+ sign in permissions)
ls -l file.txt
-rw-r--r--+ 1 user group 1024 Dec 1 10:00 file.txt

# View ACLs
getfacl file.txt

# View ACLs for multiple files
getfacl file1.txt file2.txt

# Recursive view
getfacl -R directory/

Setting ACLs

# Grant specific user permission
setfacl -m u:john:rw file.txt      # User john gets read/write

# Grant specific group permission
setfacl -m g:developers:rwx dir/   # Group developers gets full access

# Set default ACL for directory (inherited by new files)
setfacl -d -m u:alice:rw dir/      # Default for user alice
setfacl -d -m g:staff:r dir/       # Default for group staff

# Multiple ACL entries
setfacl -m u:bob:rwx,g:admin:rx file.txt

# Copy ACLs from one file to another
getfacl file1.txt | setfacl --set-file=- file2.txt

Modifying and Removing ACLs

# Modify existing ACL
setfacl -m u:john:r file.txt       # Change john's permission to read-only

# Remove specific ACL entry
setfacl -x u:john file.txt         # Remove john's ACL
setfacl -x g:developers dir/       # Remove developers group ACL

# Remove all ACLs
setfacl -b file.txt                # Remove all ACL entries

# Remove default ACLs
setfacl -k dir/                    # Remove default ACLs from directory

ACL Mask

# The mask limits the maximum permissions for users and groups
setfacl -m m::r file.txt           # Set mask to read-only

# Recalculate mask
setfacl --recalculate-mask file.txt

Practical Security Scenarios

Scenario 1: Web Server Setup

# Web content directory
mkdir -p /var/www/mysite
chown -R www-data:www-data /var/www/mysite
chmod -R 755 /var/www/mysite

# Uploads directory (writable by web server)
mkdir /var/www/mysite/uploads
chmod 775 /var/www/mysite/uploads

# Configuration files (readable only by web server)
chmod 640 /var/www/mysite/config.php
chown root:www-data /var/www/mysite/config.php

Scenario 2: Shared Project Directory

# Create shared directory for team collaboration
mkdir /projects/alpha
groupadd alpha-team
chgrp alpha-team /projects/alpha
chmod 2770 /projects/alpha        # SGID for group inheritance

# Add users to team
usermod -a -G alpha-team alice
usermod -a -G alpha-team bob

# Set default ACLs for new files
setfacl -d -m g:alpha-team:rwx /projects/alpha
setfacl -d -m o::--- /projects/alpha

Scenario 3: Secure Backup Directory

# Create backup directory
mkdir /backups
chmod 700 /backups
chown backup-user:backup-group /backups

# Set immutable attribute (even root cannot delete without removing attribute)
chattr +i /backups/critical-backup.tar.gz

# View attributes
lsattr /backups/

# Remove immutable attribute when needed
chattr -i /backups/critical-backup.tar.gz

Scenario 4: Multi-User System

# User home directories
chmod 700 /home/*                 # Private home directories
# or
chmod 755 /home/*                 # Allow others to access public files

# Shared resources
mkdir /shared
chmod 1777 /shared                # Like /tmp - anyone can use, sticky bit set

# Department directories
mkdir /dept/finance
chgrp finance /dept/finance
chmod 2770 /dept/finance          # SGID for group collaboration

Security Best Practices

File Permission Guidelines

# Critical system files
chmod 644 /etc/passwd            # World readable (needed for user lookups)
chmod 640 /etc/shadow            # Root and shadow group only
chmod 600 /etc/ssh/ssh_host_*key # Private SSH keys

# User files
chmod 700 ~/.ssh                 # SSH directory
chmod 600 ~/.ssh/id_rsa         # Private keys
chmod 644 ~/.ssh/id_rsa.pub     # Public keys
chmod 600 ~/.ssh/authorized_keys # Authorized keys

# Web files
chmod 755 /var/www/html         # Web root
chmod 644 /var/www/html/*.html  # Static content
chmod 640 /var/www/html/*.php   # Scripts (readable by web server group)

# Log files
chmod 640 /var/log/*.log        # Readable by root and adm group
chmod 755 /var/log              # Log directory

Finding and Fixing Insecure Permissions

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

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

# Find unowned files
find / -nouser -o -nogroup 2>/dev/null

# Find SUID/SGID files
find / -perm -4000 -o -perm -2000 2>/dev/null

# Fix overly permissive files
find /home -type f -perm 777 -exec chmod 644 {} \;
find /home -type d -perm 777 -exec chmod 755 {} \;

# Audit home directory permissions
for dir in /home/*; do
    echo "Checking $dir"
    ls -ld "$dir"
    find "$dir" -type f -perm -o+w 2>/dev/null
done

Permission Hardening Script

#!/bin/bash
# Security audit and fix script

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

# Check for world-writable files
echo "Checking for world-writable files..."
WORLD_WRITABLE=$(find / -path /proc -prune -o -path /sys -prune -o -perm -002 -type f -print 2>/dev/null)
if [ ! -z "$WORLD_WRITABLE" ]; then
    echo "WARNING: World-writable files found:"
    echo "$WORLD_WRITABLE"
fi

# Check SUID files
echo "Checking SUID files..."
SUID_FILES=$(find / -path /proc -prune -o -perm -4000 -type f -print 2>/dev/null)
echo "SUID files found (review for necessity):"
echo "$SUID_FILES" | head -20

# Check SSH permissions
echo "Checking SSH configurations..."
for user_home in /home/*; do
    if [ -d "$user_home/.ssh" ]; then
        ssh_perms=$(stat -c %a "$user_home/.ssh")
        if [ "$ssh_perms" != "700" ]; then
            echo "WARNING: $user_home/.ssh has incorrect permissions: $ssh_perms (should be 700)"
        fi
    fi
done

# Check for files without owners
echo "Checking for unowned files..."
find / -path /proc -prune -o -nouser -print 2>/dev/null | head -20

Troubleshooting Common Permission Issues

Issue 1: Permission Denied

# Diagnosis steps
ls -l problematic_file
whoami
groups
id

# Check parent directory permissions
ls -ld $(dirname problematic_file)

# Check ACLs
getfacl problematic_file

# Trace system calls to see exact failure
strace -e open,access command_that_fails 2>&1 | grep -i denied

Issue 2: Cannot Execute Script

# Check if file has execute permission
ls -l script.sh

# Add execute permission
chmod +x script.sh
# or
chmod u+x script.sh

# Check shebang line
head -1 script.sh

# Check if filesystem mounted with noexec
mount | grep noexec

Issue 3: Cannot Access Directory

# Need execute permission to traverse directory
chmod +x directory/

# Check all parent directories
namei -l /path/to/deep/directory

# Fix directory path permissions
find /path -type d -exec chmod +x {} \;

Issue 4: Group Permissions Not Working

# Verify group membership
groups username

# Check effective group
id username

# User may need to log out/in after group change
# Or use newgrp for immediate effect
newgrp groupname

Advanced Permission Concepts

Capabilities (Fine-grained Privileges)

# View file capabilities
getcap /usr/bin/ping

# Set capability
setcap cap_net_raw+ep /usr/bin/ping

# Remove capability
setcap -r /usr/bin/ping

# List all files with capabilities
getcap -r / 2>/dev/null

SELinux Context (Red Hat/CentOS/Fedora)

# View SELinux context
ls -Z file.txt

# Change context
chcon -t httpd_sys_content_t /var/www/html/index.html

# Restore default context
restorecon -v /var/www/html/index.html

# Check SELinux status
getenforce
sestatus

AppArmor Profiles (Ubuntu/Debian)

# Check AppArmor status
aa-status

# List enforced profiles
aa-enforced

# Put profile in complain mode
aa-complain /usr/sbin/nginx

# Enforce profile
aa-enforce /usr/sbin/nginx

Practical Exercises

Exercise 1: Create a Secure Shared Directory

# Create a shared directory for a project team
sudo mkdir /projects/secret-project
sudo groupadd project-team
sudo chgrp project-team /projects/secret-project
sudo chmod 2770 /projects/secret-project

# Add users to the team
sudo usermod -a -G project-team alice
sudo usermod -a -G project-team bob

# Set default ACLs
sudo setfacl -d -m g:project-team:rwx /projects/secret-project
sudo setfacl -d -m o::--- /projects/secret-project

# Verify
ls -ld /projects/secret-project
getfacl /projects/secret-project

Exercise 2: Secure Script Deployment

# Create a script that needs elevated privileges
sudo nano /usr/local/bin/backup-system.sh

# Set ownership and permissions
sudo chown root:admin /usr/local/bin/backup-system.sh
sudo chmod 750 /usr/local/bin/backup-system.sh

# If script needs to run as root, use sudo instead of SUID
# Add to sudoers
echo "admin ALL=(root) NOPASSWD: /usr/local/bin/backup-system.sh" | sudo tee /etc/sudoers.d/backup

Exercise 3: Fix Permission Problems

# Simulate permission issues
mkdir test-perms
cd test-perms

# Create files with various permissions
touch file1.txt file2.txt file3.txt
chmod 000 file1.txt
chmod 200 file2.txt
chmod 400 file3.txt

# Try operations and fix
cat file1.txt          # Fails
chmod +r file1.txt     # Fix

echo "test" > file2.txt # Fails initially
chmod u+w file2.txt    # Already has write, needs read
chmod u+r file2.txt    # Fix

# Clean up
cd ..
rm -rf test-perms

Exercise 4: Audit System Permissions

#!/bin/bash
# System permission audit script

# Function to check directory permissions
audit_directory() {
    local dir=$1
    local expected_perm=$2
    local actual_perm=$(stat -c %a "$dir")

    if [ "$actual_perm" != "$expected_perm" ]; then
        echo "WARNING: $dir has permissions $actual_perm (expected $expected_perm)"
    else
        echo "OK: $dir has correct permissions ($expected_perm)"
    fi
}

# Audit critical directories
audit_directory "/etc" "755"
audit_directory "/var/log" "755"
audit_directory "/tmp" "1777"
audit_directory "/root" "700"

# Check for dangerous permissions
echo -e "\nChecking for dangerous permissions..."
find /home -type f -perm -o+w 2>/dev/null | head -10
find /etc -type f -perm -o+w 2>/dev/null

Quick Reference Commands

Essential Permission Commands

# View
ls -l              # List with permissions
ls -la             # Include hidden files
stat file          # Detailed file info
getfacl file       # View ACLs

# Modify Permissions
chmod 755 file     # Numeric method
chmod u+x file     # Symbolic method
chmod -R 644 dir/  # Recursive

# Change Ownership
chown user file    # Change owner
chgrp group file   # Change group
chown user:group   # Change both

# Special Permissions
chmod u+s file     # Set SUID
chmod g+s dir/     # Set SGID
chmod +t dir/      # Set sticky bit

# ACLs
setfacl -m u:user:rwx file  # Set ACL
setfacl -x u:user file       # Remove ACL
setfacl -b file              # Remove all ACLs

# Find Files by Permission
find / -perm 777            # Exact permission
find / -perm -777           # At least these permissions
find / -perm /777           # Any of these permissions

Common Permission Patterns

Standard File Permissions

  • 644 (rw-r--r--): Regular files
  • 600 (rw-------): Private files
  • 664 (rw-rw-r--): Group-editable files
  • 400 (r--------): Read-only private files

Standard Directory Permissions

  • 755 (rwxr-xr-x): Regular directories
  • 700 (rwx------): Private directories
  • 775 (rwxrwxr-x): Group-accessible directories
  • 1777 (rwxrwxrwt): Temporary directories
  • 2775 (rwxrwsr-x): Shared project directories

Security Checklist

  • [ ] No world-writable files in system directories
  • [ ] SUID/SGID bits only where necessary
  • [ ] Home directories are 700 or 750
  • [ ] SSH keys are 600
  • [ ] Web files not writable by web server
  • [ ] Log files readable only by authorized users
  • [ ] Regular permission audits scheduled
  • [ ] ACLs documented and reviewed
  • [ ] umask set appropriately (022 or 027)
  • [ ] Sticky bit set on shared writable directories

Key Takeaways

1. Permissions are the first line of defense in Linux 2. Follow the principle of least privilege 3. Regular audits prevent permission creep 4. Understand the difference between file and directory permissions 5. Special permissions can be security risks if misused 6. ACLs provide fine-grained control when needed 7. Different applications require different permission strategies 8. Always test permission changes in non-production first

Additional Resources