Skip to content

Permissions_ownership

Comprehensive Linux File Permissions and Access Control

Section titled “Comprehensive Linux File Permissions and Access Control”

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

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