Beyond the familiar read/write/execute bits, Linux has three special permission bits: setuid, setgid and the sticky bit. You meet them in shared directories, in /tmp, and in programs like passwd and sudo. Knowing them helps with both team setups and security audits.
Overview
| Bit | Octal | On files | On directories |
|---|---|---|---|
| setuid | 4000 | Runs as the file’s owner | (ignored on Linux) |
| setgid | 2000 | Runs with the file’s group | New files inherit the directory’s group |
| sticky | 1000 | (ignored) | Only a file’s owner can delete or rename it |
The special bits form the first digit of a four-digit mode: chmod 2775 dir, chmod 1777 /tmp.
Reading them in ls
They replace the x in the permission string:
ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root … /usr/bin/passwd # s in owner position = setuid
ls -ld /srv/shared
drwxrwsr-x 2 root webteam … /srv/shared # s in group position = setgid
ls -ld /tmp
drwxrwxrwt 15 root root … /tmp # t in others position = sticky
A lowercase s or t means the bit is set and the underlying execute bit is too. An uppercase S or T means the special bit is set without execute. That’s usually a mistake, for example chmod 2664 on a directory nobody can enter.
setuid: run as the owner
When a setuid file runs, the process gets the file owner’s privileges instead of the caller’s. That’s how a normal user can change their password: /usr/bin/passwd is owned by root and setuid, so it can write /etc/shadow.
Other examples: sudo, su, mount, ping (on older systems) and newgrp.
Security: a setuid-root program with a bug, or one that can be told to run arbitrary commands, gives an attacker root. That’s why:
- Linux ignores setuid on shell scripts. Use sudo rules for scripts instead.
- You should never set setuid on general tools like
bash,find,vimorpython. Each of those can spawn a root shell. - Filesystems for untrusted content should be mounted
nosuid.
chmod u+s file # set (or chmod 4755 file)
chmod u-s file # remove
setgid on directories: shared group folders
This is the most useful special bit in day-to-day admin work. On a directory, setgid makes every new file and subdirectory inherit the directory’s group instead of the creator’s primary group:
sudo groupadd webteam
sudo chown root:webteam /srv/shared
sudo chmod 2775 /srv/shared # or: chmod g+s /srv/shared
Now when alice creates /srv/shared/report.txt, it belongs to group webteam, so bob (also in webteam) can work with it. Subdirectories inherit the setgid bit too, so the whole tree stays consistent.
Combine it with a 002 umask, or default ACLs, so files are also group-writable. See umask and Linux groups.
On files, setgid makes the program run with the file’s group. It’s used by a few system tools, such as wall and write (group tty).
Sticky bit: protect files in shared directories
In a world-writable directory, anyone could normally delete anyone’s files. The sticky bit restricts deletion and renaming to the file’s owner, the directory owner and root:
ls -ld /tmp /var/tmp
drwxrwxrwt …
Use it on any directory where several users write but shouldn’t touch each other’s files:
sudo mkdir /srv/dropbox
sudo chmod 1777 /srv/dropbox # or: chmod +t /srv/dropbox
Setting and removing with chmod
chmod 4755 file # setuid + 755
chmod 2775 dir # setgid + 775
chmod 1777 dir # sticky + 777
chmod g+s dir # symbolic
chmod o+t dir
chmod u-s,g-s file # remove
Note: a plain numeric chmod 755 dir does not clear setgid on directories with GNU chmod. Clear it explicitly with chmod g-s dir, or use a five-digit mode like chmod 00755 dir.
Audit setuid and setgid files
Unexpected setuid binaries are a classic backdoor and privilege-escalation path. List them:
sudo find / -xdev -perm -4000 -type f -exec ls -l {} + 2>/dev/null # setuid
sudo find / -xdev -perm -2000 -type f -exec ls -l {} + 2>/dev/null # setgid
Compare the list against a known-good baseline, or against package ownership:
dpkg -S /usr/bin/passwd # Debian/Ubuntu: which package owns it
rpm -qf /usr/bin/passwd # RHEL family
A setuid file that no package owns, especially in /tmp, /home or /var/www, deserves immediate investigation. Tools like Lynis and AIDE automate these checks. See Linux server hardening checklist.
Capabilities: the modern alternative
Instead of full setuid root, Linux capabilities grant single privileges. For example, a non-root app can bind ports below 1024:
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/myserver
getcap /usr/local/bin/myserver
For services, systemd’s AmbientCapabilities=CAP_NET_BIND_SERVICE does the same without touching the binary.
Quick reference
| Goal | Command |
|---|---|
| Shared group folder | chmod 2775 dir |
| Shared drop folder | chmod 1777 dir |
| Remove setgid | chmod g-s dir |
| Find setuid files | find / -xdev -perm -4000 -type f |
| Bind low port without root | setcap cap_net_bind_service=+ep bin |