setuid, setgid, and the Sticky Bit
The three permission bits every sysadmin uses and few can explain end-to-end. They are small, they are old, and they decide who actually runs what.
Start with the boring part, because it is the part everything else hangs on. A file’s mode is three triplets: owner, group, other. Each triplet is read, write, execute — rwx. A directory’s execute bit means “you may traverse and stat inside it”, not “you may run it”, which is why a directory with rw- and no x is a locked room with the lights on: you can see the door, you cannot walk through it.
-rw-r–r– 1 alice dev 4096 Nov 2 09:00 notes.txt
drwxr-xr-x 2 alice dev 4096 Nov 2 09:00 shared
-rwxr-xr-x 1 root root 5420 Nov 2 09:00 deploy
That is the normal world. The three special bits live in a fourth digit, to the left of the owner triplet, and they change what “execute” and “delete” mean.
When the setuid bit is set on an executable, the kernel runs it with the effective UID of the file’s owner, not the user who launched it. That is how /usr/bin/passwd works: an ordinary user needs to write to /etc/shadow, which only root can write, so passwd runs as root just long enough to do one narrow job and then stops. Same story for sudo, which is setuid root and then decides, via its own policy, whether you are allowed to keep that power.
$ ls -l /usr/bin/passwd /usr/bin/sudo
-rwsr-xr-x 1 root root /usr/bin/passwd
-rwsr-xr-x 1 root root /usr/bin/sudo
Note the s where the owner’s execute bit would be. Lowercase s means setuid and execute; uppercase S means setuid with execute switched off, which is almost always a mistake or a leftover. Set it with chmod u+s, clear it with chmod u-s, or set the whole mode numerically: chmod 4755.
The danger is proportional to the power. A setuid-root binary with a bug, a shell escape, or a world-writable config file is a privilege escalation waiting for an audience. That is why you audit them — find / -perm -4000 -type f — and why setuid is ignored on shell scripts on Linux: the kernel will not honour it, because the interpreter, not the script, is what actually runs.
Setgid does two different jobs depending on what it is attached to. On an executable, the process runs with the file’s group instead of the caller’s group. On a directory, new files created inside it inherit the directory’s group, not the creator’s primary group. The directory case is the one you will actually use every week.
$ chmod 2775 /srv/projects/shared
$ ls -ld /srv/projects/shared
drwxrwsr-x 2 alice dev /srv/projects/shared
Now every file a team member creates in shared belongs to group dev, regardless of who created it, and the group permissions on the directory decide who can read and write. Without setgid, each person’s files land in their own primary group and the “shared” directory quietly stops being shared. Set it with chmod g+s, numerically chmod 2755 for a directory, chmod 2755 for an executable that needs group power.
The sticky bit on a directory means: you may delete or rename a file in it only if you own the file, own the directory, or are root — even if the directory itself is world-writable. That is the whole trick of /tmp. Everybody can write there, nobody can delete everybody else’s work out from under them.
$ ls -ld /tmp /var/tmp
drwxrwxrwt 12 root root /tmp
drwxrwxrwt 4 root root /var/tmp
The t in the other’s execute slot is the sticky bit, lowercase because execute is also on; uppercase T means sticky without execute. Numerically: chmod 1777 /tmp is the classic, chmod o+t is the symbolic form. On a regular file the sticky bit is a historical curiosity — it once meant “keep this program in swap” — and on modern Linux it does nothing useful. Do not go looking for a use for it there.
$ chmod 4755 /usr/local/bin/helper # setuid, runs as owner
$ chmod 2755 /srv/projects/shared # setgid directory, group inherits
$ chmod 1777 /tmp # sticky, world-writable, safe deletes
$ chmod 6755 /usr/local/bin/tool # setuid + setgid together
Read a mode like 6755 left to right: 6 is setuid (4) plus setgid (2), then 7 for owner, 5 for group, 5 for other. And the mistakes to avoid, in order of how often they actually happen: 777 as a fix for a permissions problem (it is not a fix, it is a surrender), setuid on a file that does not need it, setuid on a world-writable binary, and a shared directory without setgid that slowly fills with files nobody else on the team can edit. Fix the mode, not the symptom.
Mock-up terminal examples only — no real server output.Under the Hood
