Skip to content

Permissions and Ownership

Comprehensive Linux File Permissions and Access Control

Section titled “Comprehensive Linux File Permissions and Access Control”

File permissions are the frontline defense for Linux system security:

Permissions for DevOps/SRE
+------------------------------------------------------------------+
| |
| Security Hardening: |
| +----------------------------------------------------------+ |
| | Web root → 755 (read-only by web server) | |
| | Config files → 600 (owner only) | |
| | SSH keys → 600 (never 644!) | |
| | /tmp → 1777 with sticky bit (prevent deletion) | |
| +----------------------------------------------------------+ |
| |
| Container Security: |
| +----------------------------------------------------------+ |
| | Run as non-root user in containers | |
| | Use read-only filesystems where possible | |
| | Security contexts map to Linux permissions | |
| +----------------------------------------------------------+ |
| |
| Automation & Compliance: |
| +----------------------------------------------------------+ |
| | Ansible file permissions for secure config deployment | |
| | PCI-DSS requires specific permission patterns | |
| | Audit logs must be protected (640, owned by root) | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

Practical Impact:

  • Prevent unauthorized access to sensitive files
  • Secure SSH keys and credentials
  • Comply with security standards (PCI-DSS, HIPAA)
  • Prevent privilege escalation vulnerabilities

Linux uses a discretionary access control (DAC) model where each file and directory has:

  • Owner: The user who created or owns the file
  • Group: A group associated with the file
  • Others: Everyone else on the system
┌────────────────────────────────────────────────────────────────────────┐
│ LINUX PERMISSION MODEL │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ Each file/directory has: │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ PERMISSIONS │ │
│ │ │ │
│ │ Owner (u) │ Group (g) │ Others (o) │ │
│ │ ┌─────────┐ │ ┌─────────┐ │ ┌─────────┐ │ │
│ │ │ r │ w │ x│ │ │ r │ w │ x│ │ │ r │ w │ x│ │ │
│ │ └─────────┘ │ └─────────┘ │ └─────────┘ │ │
│ │ 4 2 1 │ 4 2 1 │ 4 2 1 │ │
│ │ │ │ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ Permission Evaluation Order: │
│ │
│ 1. Is the current user the owner? → Check owner permissions │
│ 2. Is the current user's group the → Check group permissions │
│ file's group? │
│ 3. Otherwise → Check others permissions │
│ │
│ NOTE: Owner permissions always take precedence if user is owner │
│ │
└────────────────────────────────────────────────────────────────────────┘
PermissionOn FilesOn Directories
Read (r)View file contents (cat, less)List directory contents (ls)
Write (w)Modify file (vim, echo >>)Create/delete files in directory
Execute (x)Run as program (./script)Access directory contents (cd)
┌────────────────────────────────────────────────────────────────────────┐
│ PERMISSION NUMERIC VALUES │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ Permission Set │ Numeric │ Binary │ Permission String │
│ ─────────────────────┼─────────┼────────┼─────────────────── │
│ --- │ 0 │ 000 │ No permissions │
│ --x │ 1 │ 001 │ Execute only │
│ -w- │ 2 │ 010 │ Write only │
│ -wx │ 3 │ 011 │ Write + Execute │
│ r-- │ 4 │ 100 │ Read only │
│ r-x │ 5 │ 101 │ Read + Execute │
│ rw- │ 6 │ 110 │ Read + Write │
│ rwx │ 7 │ 111 │ Full permissions │
│ │
│ Common Permission Sets: │
│ │
│ 755 │ rwxr-xr-x │ Standard for executables/scripts │
│ 644 │ rw-r--r-- │ Standard for regular files │
│ 600 │ rw------- │ Private files │
│ 700 │ rwx------ │ Private directories │
│ 777 │ rwxrwxrwx │ World-writable (avoid!) │
│ 2755 │ rwxr-sr-x │ SetGID on directory │
│ 4755 │ rwsr-xr-x │ SetUID (dangerous!) │
│ 1755 │ rwxr-xr-t │ Sticky bit │
│ │
└────────────────────────────────────────────────────────────────────────┘

Terminal window
# Format: [who][operator][permissions]
# WHO:
# u = user (owner)
# g = group
# o = others
# a = all (u+g+o)
# OPERATOR:
# + = add permission
# - = remove permission
# = = set exact permission
# PERMISSIONS:
# r = read
# w = write
# x = execute
# s = setuid/setgid
# t = sticky bit
# X = execute only if directory or already executable
# Add permissions
chmod u+x script.sh # Add execute for owner
chmod g+rw file.txt # Add read/write for group
chmod o+r file.txt # Add read for others
chmod a+x program # Add execute for all
chmod +x script.sh # Same as a+x
# Remove permissions
chmod u-x script.sh # Remove execute from owner
chmod go-w file.txt # Remove write from group and others
chmod -r file.txt # Remove read from all
chmod o-rwx file.txt # Remove all from others
# Set exact permissions
chmod u=rwx file.sh # Set exactly rwx for owner
chmod go=rw file.txt # Set exactly rw for group/others
chmod a=r file.txt # Set exactly r for all
chmod = file.txt # Remove all permissions
# Multiple operations
chmod u+x,g+rw file.txt # Multiple changes at once
chmod u=rwx,g=rw,o=r file # Different for each
# Copy permissions
chmod --reference=file1.txt file2.txt
Terminal window
# Using octal numbers
chmod 644 file.txt # rw-r--r--
chmod 755 script.sh # rwxr-xr-x
chmod 600 secret.txt # rw-------
chmod 700 private_dir # rwx------
chmod 777 public # rwxrwxrwx (dangerous!)
# Special permissions with numeric
chmod 4755 program # SetUID + rwxr-xr-x
chmod 2755 directory # SetGID + rwxr-sr-x
chmod 1755 directory # Sticky bit + rwxr-xr-t
chmod 6755 program # SetUID + SetGID + rwsr-sr-x
# What each digit means:
# First digit: special (4=SetUID, 2=SetGID, 1=Sticky)
# Second digit: owner permissions
# Third digit: group permissions
# Fourth digit: others permissions
Terminal window
# Apply to all files in directory
chmod -R 755 /path/to/dir
# Only apply to directories
find /path -type d -exec chmod 755 {} \;
# Only apply to files
find /path -type f -exec chmod 644 {} \;
# Combine
chmod -R u=rwX,g=rX,o=rX /path
# Note: X = execute only for directories or files with existing execute
# Using find with permissions
find /var/www -type f -exec chmod 644 {} +
find /var/www -type d -exec chmod 755 {} +
# Modern approach (faster)
chmod -R u+rwX,g+rwX,o=rX /path
Terminal window
# Web server files
chmod -R 644 /var/www/html
chmod -R 755 /var/www/cgi-bin
chmod 644 /var/www/html/index.html
# SSH keys
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
chmod 700 ~/.ssh
# Shell scripts
chmod 755 /usr/local/bin/myscript
chmod +x script.sh
# Configuration files
chmod 600 /etc/myapp/config.conf
chmod 640 /etc/myapp/app.conf
# Log files (append only)
chmod 640 /var/log/app.log
chattr +a /var/log/app.log
# Directories
chmod 755 /home/user
chmod 700 /home/user/private

Terminal window
# Change owner only
sudo chown username file.txt
sudo chown john file.txt
# Change owner and group
sudo chown username:groupname file.txt
sudo chown john:developers file.txt
# Change group only
sudo chown :groupname file.txt
sudo chown :developers file.txt
# Same as above
sudo chgrp developers file.txt
# Change owner recursively
sudo chown -R username /path/to/dir
# Change owner and group recursively
sudo chown -R username:groupname /path/to/dir
Terminal window
# Copy ownership from another file
chown --reference=original.txt new.txt
# Preserve ownership during copy
cp -a source dest
cp -p source dest
# Use rsync with ownership
rsync -aO source/ dest/
Terminal window
# Using numeric IDs
sudo chown 1000:1000 file.txt
sudo chown :1000 file.txt
# Find UID/GID of user
id username
id -u username
id -g username
# Change using ID
sudo chown 1000:1000 file.txt
Terminal window
# Change owner of symbolic link (not target)
chown -h user linkname
# Change owner recursively but not follow symlinks
chown -HR user /path
# Only change if already owned by specified user
chown --from=john mary file.txt
# Change files owned by one user to another
find /path -user olduser -exec chown newuser {} \;
# Change group for files owned by specific group
find /path -group oldgroup -exec chgrp newgroup {} \;

┌────────────────────────────────────────────────────────────────────────┐
│ SETUID PERMISSION │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ What it does: │
│ When a file with SetUID is executed, it runs with the permissions │
│ of the file's OWNER, not the user running it. │
│ │
│ Security Implication: │
│ - Very powerful, can lead to privilege escalation │
│ - Only use when absolutely necessary │
│ - Should never have SetUID on shell scripts │
│ │
│ Examples: │
│ - /usr/bin/passwd (4,755) - runs as root to change passwords │
│ - /usr/bin/su (4,755) - runs as root to switch users │
│ - /usr/bin/mount (4,755) - runs as root to mount filesystems │
│ - /usr/bin/umount (4,755) - runs as root to unmount │
│ │
│ How to identify: │
│ ls -l /usr/bin/passwd │
│ -rwsr-xr-x 1 root root 68000 Jan 15 10:30 /usr/bin/passwd │
│ ^ │
│ └── 's' instead of 'x' in owner execute │
│ │
│ Setting: │
│ chmod 4755 program │
│ chmod u+s program │
│ │
│ Removing: │
│ chmod 0755 program │
│ chmod u-s program │
│ │
└────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────┐
│ SETGID PERMISSION │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ On Files: │
│ - Runs with permissions of file's GROUP │
│ - Similar to SetUID but for group │
│ - Rarely used on files │
│ │
│ On Directories: │
│ - New files/dirs inherit the group from the directory │
│ - Essential for shared group directories │
│ │
│ Example: /var/www (web server group) │
│ chmod 2775 /var/www │
│ chown :www-data /var/www │
│ │
│ Any file created in /var/www will have www-data group │
│ │
│ How to identify: │
│ ls -ld /var/www │
│ drwxrwsr-x 2 root www-data 4096 Jan 15 10:30 /var/www │
│ ^ │
│ └── 's' instead of 'x' in group execute │
│ │
│ Setting: │
│ chmod 2775 /shared │
│ chmod g+s /shared │
│ │
└────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────┐
│ STICKY BIT │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ What it does: │
│ On directories, only the owner (or root) can delete or rename │
│ files within that directory, even if others have write permission │
│ │
│ Use cases: │
│ - /tmp (world-writable temp directory) │
│ - Shared directories where users can create files │
│ - Prevents users from deleting others' files │
│ │
│ How to identify: │
│ ls -ld /tmp │
│ drwxrwxrwt 10 root root 4096 Jan 15 10:30 /tmp │
│ ^ │
│ └── 't' instead of 'x' in others execute │
│ │
│ Setting: │
│ chmod 1777 /tmp │
│ chmod +t /tmp │
│ │
│ Removing: │
│ chmod 777 /tmp │
│ chmod -t /tmp │
│ │
└────────────────────────────────────────────────────────────────────────┘

Terminal window
# Basic output
ls -l file.txt
-rw-r--r-- 1 john developers 1024 Jan 15 10:30 file.txt
# Breakdown:
# - = file type (- = regular, d = directory, l = symlink)
# rw- = owner permissions (rw-)
# r-- = group permissions (r--)
# r-- = other permissions (r--)
# 1 = number of hard links
# john = owner
# developers = group
# 1024 = size in bytes
# Jan 15 10:30 = modification time
# file.txt = filename
CharacterType
-Regular file
dDirectory
lSymbolic link
cCharacter device
bBlock device
pNamed pipe (FIFO)
sSocket
Terminal window
# Numeric format
stat -c "%a %n" file.txt
# Output: 644 file.txt
# Detailed access control lists
getfacl file.txt
# Show permission in binary
python3 -c "print(f'{644:012b}')"
# 110100100
# Show in human readable
stat -c "%A (%a) %n" file.txt
# -rw-r--r-- (644) file.txt
# Show owner and group numerically
stat -c "%U:%G %a %n" file.txt
# john:developers 644 file.txt

Terminal window
# Install if needed
sudo apt-get install acl
# View ACL
getfacl file.txt
# Set ACL for user
setfacl -m u:john:rw file.txt
# Set ACL for group
setfacl -m g:developers:rw file.txt
# Set ACL for others
setfacl -m o::r file.txt
# Remove specific ACL
setfacl -x u:john file.txt
# Remove all ACLs
setfacl -b file.txt
Terminal window
# Default ACL for directory (new files inherit)
setfacl -R -m d:u:john:rw /path/to/dir
# Set default for groups
setfacl -R -m d:g:developers:rw /path/to/dir
# View default ACLs
getfacl /path/to/dir
# Remove default ACL
setfacl -k /path/to/dir
Terminal window
# Give specific user read/write
setfacl -m u:bob:rw- /shared/file.txt
# Give group read access
setfacl -m g:team:r-- /shared/file.txt
# Multiple ACLs
setfacl -m u:alice:rwx,u:bob:rw-,g:team:r-- file.txt
# Copy ACL from another file
getfacl file1.txt | setfacl -b -f - file2.txt
# Backup and restore ACLs
getfacl -R /path > acl_backup.txt
setfacl -R --restore=acl_backup.txt
Terminal window
# The effective permissions are determined by (owner permissions & mask)
# Default mask is usually the group permissions
# Set mask
setfacl -m m::r file.txt
# View mask
getfacl file.txt | grep mask

┌────────────────────────────────────────────────────────────────────────┐
│ UMASK EXPLAINED │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ umask subtracts from default permissions │
│ │
│ Default file permissions: 666 (rw-rw-rw-) │
│ Default dir permissions: 777 (rwxrwxrwx) │
│ │
│ umask 022: │
│ File: 666 - 022 = 644 (rw-r--r--) │
│ Dir: 777 - 022 = 755 (rwxr-xr-x) │
│ │
│ Common umask values: │
│ ┌─────────┬────────────┬────────────┐ │
│ │ umask │ File │ Directory │ │
│ ├─────────┼────────────┼────────────┤ │
│ │ 000 │ 666 │ 777 │ │
│ │ 022 │ 644 │ 755 │ (default) │
│ │ 027 │ 640 │ 750 │ │
│ │ 077 │ 600 │ 700 │ (restrictive) │
│ │ 133 │ 644 │ 644 │ │
│ └─────────┴────────────┴────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘
Terminal window
# View current umask
umask
# Set for current session
umask 022
# Set in ~/.bashrc or ~/.profile
echo "umask 022" >> ~/.bashrc
# Set for all users (system-wide)
echo "umask 022" >> /etc/profile
echo "umask 022" >> /etc/bash.bashrc
# Set for specific service
# In /etc/pam.d/sshd
session optional pam_umask.so umask=0027

Terminal window
# DANGEROUS - Never do this!
chmod 777 file # Anyone can modify!
chmod -R 777 /directory # Huge security hole!
chmod +s file # SetUID without understanding
# Safer alternatives
chmod 755 /directory # Owner full, others read/execute
chmod 644 file # Owner rw, others read
chmod 600 keyfile # Owner only
secure-permissions.sh
#!/bin/bash
# Web server
chown -R www-data:www-data /var/www
find /var/www -type f -exec chmod 644 {} \;
find /var/www -type d -exec chmod 755 {} \;
# SSH keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/*
chmod 644 ~/.ssh/*.pub
# Configuration files
chmod 600 /etc/app/config.conf
# Log files
chown -R root:adm /var/log/app
find /var/log/app -type f -exec chmod 640 {} \;
┌────────────────────────────────────────────────────────────────────────┐
│ PERMISSION SECURITY CHECKLIST │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ Files: │
│ □ Private keys: 600 (owner only) │
│ □ Config files: 640 or 600 │
│ □ Scripts: 755 (if executable) or 644 │
│ □ Data files: 644 or 600 │
│ □ Sensitive data: 600 │
│ │
│ Directories: │
│ □ Private: 700 (owner only) │
│ □ Shared: 750 with appropriate group │
│ □ Public writable with sticky bit: 1777 │
│ │
│ Special: │
│ □ Avoid SetUID unless absolutely necessary │
│ □ Use SetGID for shared group directories │
│ □ Use sticky bit on /tmp-like directories │
│ │
│ Review: │
│ □ Regular permission audits │
│ □ Check for world-writable files │
│ □ Monitor for new SetUID binaries │
│ │
└────────────────────────────────────────────────────────────────────────┘

Terminal window
# Permission denied error
ls -l /path/to/file
# Check owner and permissions
# Cannot delete file
ls -ld /directory
# Check directory permissions and sticky bit
# Cannot access directory
ls -ld /path
# Check execute permission on each parent
# "Operation not permitted" even as root
lsattr file
# Check for immutable attribute
# Cannot change permissions
ls -l file
# Check if file is on NFS with nosuid
# "Too many levels of symbolic links"
file link
# Check circular links
Terminal window
# Check who owns the file
stat file.txt
# Check effective permissions for current user
namei -l /path/to/file
# Check ACLs
getfacl file.txt
# Check attributes
lsattr file.txt
# Check process capabilities
getpcaps <pid>
# Monitor permission changes
inotifywait -m -r -e mode /path &

Q1: What is the difference between chmod 755 and chmod 655?

Section titled “Q1: What is the difference between chmod 755 and chmod 655?”

Answer:

  • chmod 755: rwxr-xr-x (owner: rwx, group: r-x, others: r-x)

    • Owner can read, write, execute
    • Group and others can read and execute
  • chmod 655: rw-r-xr-x (owner: rw-, group: r-x, others: r-x)

    • Owner can read and write (not execute)
    • Group and others can read and execute

The difference is that 755 allows execute for owner, while 655 does not.

Q2: What does the SetUID bit do and why is it dangerous?

Section titled “Q2: What does the SetUID bit do and why is it dangerous?”

Answer: The SetUID (suid) bit makes a program run with the permissions of the file’s owner (usually root), regardless of who executes it.

Danger:

  • If the program has vulnerabilities, any user can exploit them with root privileges
  • Shell scripts with SetUID are especially dangerous (injection attacks)
  • Many privilege escalation exploits target SetUID binaries

Safe examples:

  • /usr/bin/passwd needs it to modify /etc/shadow
  • /usr/bin/su needs it to switch users

Best practice: Avoid SetUID on custom programs; use sudo instead.

Q3: How would you give a user read/write access to a specific file without affecting others?

Section titled “Q3: How would you give a user read/write access to a specific file without affecting others?”

Answer:

Terminal window
# Using ACL
setfacl -m u:username:rw- /path/to/file
# Or change ownership
sudo chown username:groupname /path/to/file
sudo chmod 640 /path/to/file

ACL is more flexible as it doesn’t change the primary owner.

Q4: What is the sticky bit and where is it commonly used?

Section titled “Q4: What is the sticky bit and where is it commonly used?”

Answer: The sticky bit on directories prevents users from deleting or renaming files they don’t own, even if they have write permission to the directory.

Common uses:

  • /tmp - allows anyone to create files but not delete others
  • Shared directories where users need to create files

Without sticky bit, any user with write access could delete any file in the directory.

Q5: What happens when you set execute permission on a directory?

Section titled “Q5: What happens when you set execute permission on a directory?”

Answer: Execute permission on a directory allows:

  • Entering (cd) into the directory
  • Accessing files within (if you have permission to those files)
  • Using the directory as part of a path

Without execute, you cannot access anything inside, even if you have read permission on the files.

Q6: What is the difference between chmod -R and chmod -R?

Section titled “Q6: What is the difference between chmod -R and chmod -R?”

Answer:

  • chmod -R - Applies recursively to all files and directories
  • chmod -R (capital R) - Same as above but follows symbolic links

Be careful: chmod -R 777 / would be catastrophic!

Use -X (capital X) for safe recursion that only applies execute to directories.

Q7: How do you find all SetUID binaries on your system?

Section titled “Q7: How do you find all SetUID binaries on your system?”

Answer:

Terminal window
# Find all SetUID files
find / -perm /4000 2>/dev/null
# Find SetGID files
find / -perm /2000 2>/dev/null
# Find both
find / -perm /6000 2>/dev/null
# More readable output
find / -perm /4000 -ls 2>/dev/null

Answer: umask sets the default permissions for newly created files and directories by masking (subtracting) bits from the default permissions.

  • Default file: 666
  • Default directory: 777
  • umask 022 removes write for group/others

This ensures files aren’t accidentally created with overly permissive access.


Terminal window
# Change mode
chmod 644 file # Numeric
chmod u+x file # Symbolic
chmod -R 755 dir # Recursive
# Change owner
chown user:group file # Owner and group
chown user file # Owner only
chgrp group file # Group only
# View
ls -l file # Details
stat file # Full info
getfacl file # ACLs
# Special bits
chmod u+s file # SetUID
chmod g+s dir # SetGID
chmod +t dir # Sticky bit
OctalBinaryPermission
0000---
1001—x
2010-w-
3011-wx
4100r—
5101r-x
6110rw-
7111rwx
ValueUse Case
600Private file
644Public file
700Private directory
755Executable/public dir
775Shared group dir
777Public writable

Terminal window
# ❌ WRONG: World-writable is a security risk
chmod 777 /etc/myapp/config # Anyone can read/modify!
chmod -R 777 /opt/myapp # HORRIBLE practice!
# ✅ CORRECT: Use minimum necessary permissions
chmod 640 /etc/myapp/config # Owner rw, group r, others none
chmod 755 /opt/myapp/bin # Owner rwx, group r-x, others r-x
Terminal window
# ❌ WRONG: Leaving dangerous SetUID binaries
# /usr/bin/passwd has SetUID (needed) - but others shouldn't!
find / -perm -4000 2>/dev/null # Check for SetUID
# Unknown SetUID binaries = potential privilege escalation
# ✅ CORRECT: Audit SetUID/SetGID regularly
find / -perm -4000 -user root 2>/dev/null | grep -v "/usr/bin/passwd"
# Remove SetUID if not needed: chmod u-s /path/to/binary
Terminal window
# ❌ WRONG: Too permissive umask
umask 000 # Files created with 777!
# ✅ CORRECT: Secure umask
umask 077 # Files: 700, directories: 777
# Add to ~/.bashrc or /etc/profile
Terminal window
# ❌ WRONG: Trying to solve everything with basic permissions
# Need 3+ groups with different access?
# Basic permissions only support owner, group, other!
# ✅ CORRECT: Use ACLs for fine-grained access
setfacl -m g:developers:rw /shared/file
setfacl -m g:qasales:r /shared/file
getfacl /shared/file # View all ACLs

In this chapter, you learned:

  • ✅ Permission model (owner, group, others)
  • ✅ chmod numeric and symbolic modes
  • ✅ chown and chgrp for ownership
  • ✅ Special permissions (SetUID, SetGID, sticky bit)
  • ✅ Viewing and interpreting permissions
  • ✅ Access Control Lists (ACLs)
  • ✅ umask and default permissions
  • ✅ Security best practices
  • ✅ Troubleshooting common issues
  • ✅ Interview questions and answers

Chapter 9: sudo and Privilege Escalation


Last Updated: February 2026