How do Linux file permissions work — chmod, chown, setuid, setgid, sticky bit?
Quick Answer
Linux controls file access with three levels: owner, group, and others. Each gets read (r=4), write (w=2), and execute (x=1) bits. chmod changes permissions, chown changes ownership. Special bits include setuid (run as file owner), setgid (inherit directory group), and sticky bit (only owner can delete).
Detailed Answer
Think of Linux file permissions like security badges in an office building. Each file is a room with three tiers of access: the room owner (user), the department (group), and everyone else (others). Each tier independently controls whether you can read documents (r), modify them (w), or run procedures (x). Special permissions act like master keys: setuid lets anyone run a program as if they were the owner, setgid makes new files inherit the department's group, and the sticky bit stops people from deleting each other's files in shared spaces.
The basic model uses nine bits in three groups of three: user (owner), group, and others. Each group has read (r/4), write (w/2), and execute (x/1). For regular files, read lets you view content, write lets you change it, and execute lets you run it as a program. For directories, the meanings shift slightly: read lets you list contents (ls), write lets you create or delete entries (but you also need execute), and execute lets you enter the directory (cd) and access files inside it. This directory execute bit is often misunderstood. A directory with r-- lets you list filenames but not access anything in them. chmod sets permissions using either octal (chmod 750 file) or symbolic notation (chmod u+rwx,g+rx,o-rwx file). The umask value (usually 022) controls default permissions for new files by masking bits from 666 (files) or 777 (directories).
Inside the filesystem, permissions are stored in the file's inode as a 16-bit mode field. The lower 12 bits hold the permissions: bits 0-8 for the nine rwx positions and bits 9-11 for the special permissions (sticky, setgid, setuid). When a process tries to access a file, the kernel's permission check compares the process's effective user and group IDs against the file's owner and group. If the user ID matches the owner, the owner bits are checked. If not but a group ID matches, the group bits apply. Otherwise, the 'others' bits are used. Root (or more precisely, the CAP_DAC_OVERRIDE capability) bypasses all of this. Access Control Lists (ACLs), managed with setfacl and getfacl, extend the basic model by letting you set permissions for specific individual users and groups.
In production, good permission management is critical for security. Web servers typically need the www-data user to read app files (644) and traverse directories (755) but should never be able to execute uploaded files. Database data directories should be owned by the database user with tight permissions (700). The setuid bit (chmod 4755) is used by system tools like passwd and sudo. When you run a setuid program, your process runs with the file owner's user ID (usually root), giving it elevated privileges by design. The setgid bit (chmod 2755) on directories causes new files created inside to automatically inherit the directory's group ownership, which is essential for shared project folders where multiple team members need access without manually running chgrp. The sticky bit (chmod 1777) on directories like /tmp stops users from deleting or renaming files they do not own, even if they have write permission on the directory.
A dangerous gotcha is that setuid on shell scripts is ignored by the kernel on most modern systems because of historical race condition exploits. Another common mistake is running chmod -R 777 to 'fix' permission issues, which opens everything to the world and creates serious security holes. In Docker containers, files created by root inside the container show up as root-owned on the host, complicating volume management. The fix is using the --user flag or setting up user namespace remapping. Also, moving files across filesystems with mv changes ownership to your user ID because mv does a copy-and-delete across filesystem boundaries, while mv within the same filesystem just updates directory entries and preserves ownership. Regularly audit setuid binaries with find / -perm -4000 -type f to catch unauthorized privilege escalation.