Skip to content

File Permissions

Every file and directory in Linux has:

  • An owner (a user)
  • An owning group
  • A permission bitmask that controls what the owner, the group, and everyone else can do
Terminal window
ls -l myfile
# -rw-rw-r-- 1 owl devs 1024 Mar 2 19:00 myfile
# ^^^^^^^^^ ^ ^^^ ^^^
# perms links owner group
Terminal window
sudo chown alice myfile # change owner to alice
sudo chown alice:devs myfile # change owner and group
sudo chown :devs myfile # change only group (same as chgrp)
sudo chgrp devs myfile # change group
sudo chown -R alice:devs mydir/ # recursive (entire directory tree)

Linux uses 9 permission bits arranged in three triplets: owner, group, other (world):

rwx rwx rwx
^ ^ ^
| | others
| group
owner

Permission bits diagram

Each bit:

BitSymbolNumeric valueMeaning on fileMeaning on directory
Readr4View file contentsList directory contents (ls)
Writew2Modify file contentsCreate/delete/rename files inside
Executex1Run as programEnter directory (cd) and access contents

Each triplet is the sum of its active bits (0-7):

SumBinaryPermission
7111rwx (all)
6110rw-
5101r-x
4100r—
0000--- (none)

Full three-digit examples:

ModeOwnerGroupOtherTypical Use
755rwxr-xr-xDirectories, executable files
644rw-r—r—Regular files
600rw-------Private files (SSH keys)
700rwx------Private directories
777rwxrwxrwxWorld-writable (avoid!)

chmod numeric examples

Terminal window
# Numeric mode
chmod 755 script.sh # rwxr-xr-x
chmod 644 config.txt # rw-r--r--
chmod -R 750 mydir/ # recursive
# Symbolic mode
chmod u+x script.sh # add execute for owner
chmod g-w shared.txt # remove write for group
chmod o-r private.key # remove read for others
chmod a+r public.html # add read for all (a = u+g+o)
chmod ug=rw,o=r file.txt # set exact permissions
chmod go= secret.txt # remove all perms for group and other

chmod symbolic examples

chmod combined examples


When a new file or directory is created, the OS starts with a maximum permission and subtracts the umask:

  • Files start at 0666 (rw-rw-rw-)
  • Directories start at 0777 (rwxrwxrwx)
  • The umask is subtracted (bitwise AND with complement)
Terminal window
umask # display current umask (e.g., 0022)
umask 0027 # set umask for this session

With the default umask of 0022:

  • Files: 0666 & ~022 = 0644 (rw-r—r—)
  • Dirs: 0777 & ~022 = 0755 (rwxr-xr-x)

With umask 0002 (typical for User Private Groups):

  • Files: 0666 & ~002 = 0664 (rw-rw-r—)
  • Dirs: 0777 & ~002 = 0775 (rwxrwxr-x)
umaskFilesDirsUse case
0022644755Default (root’s umask)
0002664775Default for users with UPG (group-collaborative)
0027640750Group can read, others nothing
0077600700Private (others can see/access nothing)

Set permanently by adding umask XXXX to ~/.bashrc or /etc/profile.


Beyond the standard 9 bits, there are 3 special permission bits forming a 4th digit in numeric notation.

Special permissions overview

Special BitNumericSymbolicOn FilesOn Directories
SUID4s on owner xExecutes as file’s ownerNo standard effect
SGID2s on group xExecutes as file’s groupNew files inherit directory’s group
Sticky1t on other xNo standard effectOnly file owner (or root) can delete/rename

If the owner doesn’t have execute permission, the special bit shows as uppercase (S or T).

A SUID executable runs with the privileges of its owner regardless of who executes it. Classic example: passwd needs to write to /etc/shadow (root-owned), but regular users must be able to change their own password.

Terminal window
ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root 33544 ... /usr/bin/passwd
# ^
# 's' here = SUID set + owner has execute
Terminal window
chmod u+s /usr/bin/myprog # set SUID (symbolic)
chmod 4755 /usr/bin/myprog # set SUID (numeric: leading 4)

On files: Executes as the file’s group owner.

On directories: New files created inside inherit the directory’s group - perfect for shared project directories.

Terminal window
ls -l
# drwxrws--- 2 alice devs 69 ... my_articles
# ^
# 's' on group position = SGID on directory
chmod g+s project/ # set SGID on directory (symbolic)
chmod 2770 project/ # rwxrws--- for owner+group (numeric: leading 2)

On a directory, the sticky bit restricts who can delete files. Even if everyone has write access to the directory, only the file’s owner (and root) can delete it. Classic use: /tmp.

Terminal window
ls -ld /tmp
# drwxrwxrwt 15 root root 4096 ... /tmp
# ^
# 't' = sticky bit set
chmod +t /shared/ # set sticky bit (symbolic)
chmod 1777 /shared/ # rwxrwxrwt (numeric: leading 1)

Four-digit mode: XYYY where X is the special digit:

X valueBits set
0No special permissions
1Sticky only
2SGID only
3SGID + Sticky
4SUID only
5SUID + Sticky
6SUID + SGID
7All three

Standard Unix permissions allow only one owner and one group per file. ACLs let you grant fine-grained access to additional specific users or groups without changing the base ownership.

A filesystem must be mounted with ACL support (ext4, XFS support ACLs by default on modern distros).

Terminal window
# Grant specific user permissions
setfacl -m u:alice:rw myfile # alice gets rw
setfacl -m u:bob:r-- myfile # bob gets read-only
setfacl -m g:devs:rw myfile # group devs gets rw
# Deny all permissions to a user
setfacl -m u:mallory:--- myfile
# Recursive
setfacl -R -m u:alice:rwx projectdir/
# Default ACL (inherited by new files in a directory)
setfacl -dm u:alice:rw projectdir/ # -d flag = default
# Remove a specific ACL entry
setfacl -x u:alice myfile
# Remove ALL ACL entries (reset to standard Unix permissions)
setfacl -b myfile
Terminal window
getfacl myfile
# file: myfile
# owner: owl
# group: devs
# user::rw-
# user:alice:rw-
# group::rw-
# mask::rw-
# other::r--

The mask defines the maximum effective permissions for all ACL entries (except owner and other). It limits what named users and groups actually get:

Terminal window
# Set a restrictive mask (limit everyone to read-only regardless of ACL entries)
setfacl -m mask:r-- myfile
getfacl myfile
# user::rw-
# user:alice:rw- # effective: r-- (masked!)
# group::rw- # effective: r-- (masked!)
# mask::r--
# other::r--

When ACLs are present, ls -l shows a + at the end of the permission string:

Terminal window
ls -l myfile
# -rw-rw-r--+ 1 owl devs 0 Mar 2 myfile
# ^ ACL entries exist

Extended File Attributes (chattr / lsattr)

Section titled “Extended File Attributes (chattr / lsattr)”

Beyond permissions, Linux supports extended attributes that provide behaviors the kernel enforces even for root.

Terminal window
lsattr filename # view attributes
lsattr -R /etc/ # recursive view
chattr +i filename # set immutable flag
chattr -i filename # unset immutable flag
chattr +a logfile # set append-only flag
chattr =i filename # set ONLY immutable (clears all other attrs)
FlagNameBehavior
iImmutableCannot be modified, deleted, renamed, hard-linked; no data written; even root cannot touch it. Only root can set/clear this flag.
aAppend-onlyFile can only be opened in append mode; existing data cannot be modified or deleted. Ideal for log files.
dNo dumpFile is skipped by the dump backup utility. Good for swap and cache files.
ANo atime updateAccess time (atime) is not updated on reads. Reduces I/O on read-heavy files.
Terminal window
# Protect a config file from accidental modification (even by root!)
sudo chattr +i /etc/resolv.conf
sudo lsattr /etc/resolv.conf
# ----i----------- /etc/resolv.conf
# To modify it, you must first unset the flag
sudo chattr -i /etc/resolv.conf
# Make a log file append-only (can't be truncated or overwritten)
sudo chattr +a /var/log/secure
# Protect an entire directory recursively
sudo chattr -R +i /etc/ssl/
# Unprotect
sudo chattr -R -i /etc/ssl/