Table of Contents Link to heading
- Setuid: Running as the File Owner
- Setgid: Group-Inherited Permissions
- Sticky Bit: Protecting Shared Directories
- Links: Hard and Symbolic
Setuid: Running as the File Owner Link to heading
By default, when a user runs an executable, the process runs with that user’s permissions. The setuid (Set User ID) permission changes this: when set on an executable, the process runs with the permissions of the file’s owner rather than the user who invoked it.
This is how regular users can run privileged operations on specific, controlled programs without being granted broad root access. The classic examples:
/usr/bin/passwd— changes/etc/shadow, which only root can write; setuid onpasswdallows ordinary users to change their own password by temporarily running as root/usr/bin/sudo— requires setuid to authenticate and execute privileged commandsping— requires raw socket access (root-only); setuid allows regular users to runping
ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root 59640 Mar 22 2023 /usr/bin/passwd
# ^
# s = setuid + execute permission set
The s in the user execute position indicates setuid is set AND the execute permission is set. An uppercase S means setuid is set but execute is NOT set (unusual — setuid on a non-executable file has no effect).
# Add setuid (symbolic)
chmod u+s /path/to/binary
# Add setuid (numeric — add 4000 to existing permissions)
chmod 4755 /path/to/binary # rwsr-xr-x
# Remove setuid (symbolic)
chmod u-s /path/to/binary
# Remove setuid (numeric — leading 0 removes special bits)
chmod 0755 /path/to/binary # rwxr-xr-x
Setgid: Group-Inherited Permissions Link to heading
Setgid (Set Group ID) applies the same concept as setuid but at the group level. Its behaviour differs depending on whether it is set on a file or a directory.
Setgid on Executable Files Link to heading
When setgid is set on an executable, the process runs with the permissions of the file’s group rather than the executing user’s primary group:
ls -l /usr/bin/wall
# -rwxr-sr-x. 1 root tty 10996 Jul 19 2011 /usr/bin/wall
# ^
# s = setgid + group execute permission set
The wall command is owned by the tty group. When any user runs wall, the process gains tty group access, allowing it to write to terminal devices.
Setgid on Directories Link to heading
When setgid is set on a directory, new files and subdirectories created within it automatically inherit the directory’s group as their group owner — regardless of the creating user’s primary group.
This is extremely useful for shared project directories where all team members need consistent group ownership on new files:
# Without setgid: files created by different users have different group owners
# With setgid: all files in the directory are owned by the directory's group
mkdir /srv/shared
chown :developers /srv/shared
chmod g+s /srv/shared
# Now any file created in /srv/shared is automatically owned by group 'developers'
# Subdirectories also inherit the setgid bit
Configuring Setgid Link to heading
# Add setgid (symbolic)
chmod g+s /path/to/file_or_directory
# Add setgid (numeric — add 2000 to existing permissions)
chmod 2775 /srv/shared # rwxrwsr-x (directory with setgid)
# Remove setgid (symbolic)
chmod g-s /path/to/file_or_directory
# Remove setgid (numeric)
chmod 0775 /path/to/file_or_directory
Sticky Bit: Protecting Shared Directories Link to heading
The sticky bit on a directory restricts file deletion: only the file’s owner, the directory’s owner, or root can delete files within the directory — even if other users have write permission on the directory.
Without the sticky bit on a world-writable directory, any user with write access could delete any other user’s files. The sticky bit prevents this.
ls -ld /tmp
# drwxrwxrwt - root /tmp
# ^
# t = sticky bit + execute permission set for others
# (uppercase T = sticky bit set, others execute NOT set)
/tmp and /var/tmp are the canonical examples — world-writable so every process can create temporary files, but sticky so only a file’s owner can delete it.
# Add sticky bit (symbolic)
chmod o+t /shared/directory
# Add sticky bit (numeric — add 1000 to existing permissions)
chmod 1777 /shared/directory # drwxrwxrwt (standard /tmp permissions)
# Remove sticky bit (symbolic)
chmod o-t /shared/directory
# Remove sticky bit (numeric)
chmod 0777 /shared/directory
When creating shared directories for multi-user collaboration, combine setgid with appropriate group permissions:
mkdir /srv/project
chown :teamname /srv/project
chmod 2775 /srv/project # setgid + rwxrwxr-x
This ensures new files inherit the correct group, all group members can read and write, and others can only read.
Links: Hard and Symbolic Link to heading
Inodes and the Filesystem Data Model Link to heading
To understand links, the inode model is essential. Every file on a Linux filesystem is backed by an inode — a data structure that stores all metadata about the file:
- File type and permissions
- Owner (UID) and group (GID)
- File size and block count
- Timestamps (access, modification, change)
- Pointers to the data blocks on disk
Crucially, the inode does not store the filename. Filenames are stored in directory entries, which are mappings from a name to an inode number. A directory is itself a special file containing a table of (name → inode_number) pairs.
This separation of names from data is what makes multiple names for the same file (hard links) possible, and it is why moving a file within the same filesystem is instantaneous — only the directory entry changes, not the data.
ls -i /etc/passwd # show inode number
# 1234567 /etc/passwd
Hard Links Link to heading
A hard link is an additional directory entry pointing to the same inode as another file. Both names are equal — neither is the “original” — and both provide access to the same data.
ln /etc/hosts /tmp/hosts_backup # create hard link
ls -li /etc/hosts /tmp/hosts_backup
# 131073 -rw-r--r-- 2 root root 223 /etc/hosts
# 131073 -rw-r--r-- 2 root root 223 /tmp/hosts_backup
# ^
# hard link count = 2 (two names, one inode)
Hard link characteristics:
- Both names share the same inode number — they are the same file
- Deleting one name does not delete the data; data is only freed when the link count reaches zero (all names removed)
- Cannot span filesystems — inodes are filesystem-local identifiers
- Cannot link to directories (prevents filesystem loops)
- No visual indicator in
lsoutput distinguishes a hard link from a regular file
Symbolic Links Link to heading
A symbolic link (symlink) is a special file that contains a text path pointing to another file or directory. The symlink is its own inode; it stores the path string as its data.
ln -s /etc/nginx/nginx.conf /home/user/nginx.conf # create symlink
ls -la /home/user/nginx.conf
# lrwxrwxrwx 1 user user 22 /home/user/nginx.conf -> /etc/nginx/nginx.conf
# ^
# l = symbolic link file type
Symlink characteristics:
- Has its own inode, separate from the target file
- Stores the target path as its content (absolute or relative)
- Can span filesystems and mount points
- Can link to directories
- If the target is deleted or moved, the symlink becomes dangling (broken)
- Permissions shown are always
lrwxrwxrwx— actual access is determined by the target’s permissions
# Create symlinks
ln -s /path/to/target link_name
ln -s ../relative/path link_name # relative symlink
# Check if a symlink is broken
ls -la link_name # shows -> target; file not found if broken
file link_name # "broken symbolic link" if target missing
# Find all symlinks in a directory
find /etc -type l
# Find dangling (broken) symlinks
find /etc -type l ! -e # -e tests target existence
# Overwrite an existing symlink
ln -sf /new/target existing_link
Hard Links vs Symbolic Links Link to heading
| Feature | Hard Link | Symbolic Link |
|---|---|---|
| Own inode | No (shares target’s inode) | Yes (separate inode) |
| Cross-filesystem | No | Yes |
| Link to directory | No | Yes |
| Survives target deletion | Yes (data remains until all links removed) | No (becomes dangling) |
Visible as link in ls -l |
No (appears as regular file) | Yes (l type, shows ->) |
| Target path | N/A (direct inode reference) | Stored as text (absolute or relative) |
| Performance | Identical to regular file access | One extra path resolution step |
| Use case | File backup/alias within same filesystem | Configuration shortcuts, versioning (/usr/bin/python -> python3.11) |
rsync --link-dest) handle this transparently.