Special Bits Explained: setuid, setgid and the Sticky Bit

What the first digit in chmod 4755 really does — setuid, setgid and sticky bit mechanics, the s/S/t/T letters in ls -l, and when each bit is legitimate.

Published 2026-09-24

ls -l occasionally shows a mode you can’t type with three digits: -rwsr-xr-x on /usr/bin/passwd, drwxrwxrwt on /tmp. Those s and t letters are the three special bits — the reason octal modes can have a fourth digit in front. Each is a small, sharp tool: exactly one job, real consequences when misused.

The fourth digit, first

chmod [setuid+setgid+sticky][owner][group][others] file
        └─ 4 / 2 / 1 ──┘

Same sum logic as rwx: 4755 = setuid + 755, 1777 = sticky + 777, 2750 = setgid + 750, 7777 = all three (don’t). A three-digit mode leaves all three bits untouched; an explicit 0 clears them — chmod 0755 removes any setuid/setgid/sticky that was set.

In the ls -l string they borrow the execute positions — which is why the display carries a second piece of information:

display means
s in owner-x setuid and owner-execute set
S in owner-x setuid, but owner-execute not set
s in group-x setgid and group-execute set
S in group-x setgid without group-execute
t in other-x sticky and other-execute set
T in other-x sticky without other-execute

A capital letter is a warning sign in practice: setuid without execute (4600rwS------) is almost never intentional, and T usually means somebody stacked o+t onto a mode that already denied o+x.

setuid (4000): run as the owner

When an executable with setuid runs, the process gets the file owner’s effective user ID instead of the caller’s. This exists so programs can perform a narrow privileged operation for unprivileged users — /usr/bin/passwd (root-owned, 4755) lets you rewrite your own entry in a root-owned password database; sudo, su, ping (historically, for raw sockets) work the same way.

Set it with chmod u+s file or chmod 4755 file; remove with u-s. Notes that matter:

  • Ignored on scripts. Linux (and macOS) ignore setuid on interpreted files — #!/bin/sh under setuid is a race-condition festival and the kernels simply refuse to honor it. If you need the effect, write a tiny compiled wrapper that execs the script, or use a targeted sudoers rule.
  • It’s a liability surface. A setuid binary with an exploitable bug — bad argument handling, writable output paths, environment trust — is a privilege-escalation primitive. Audit what you have: find / -perm -4000 -type f 2>/dev/null. Expect a short, boring list.
  • On directories it does nothing on Linux. (On a few BSDs it once mattered; don’t rely on it.)
  • u= and a= clear it along with the owner’s rwx bits — chmod u= on 4755 yields 055, not 4755. Symmetric: -s removes just the special bit.

setgid (2000): two different jobs

On an executable, setgid runs it with the file’s group privileges — the same trick as setuid, one class over. Classic residents: wall/write (group tty, to write to other terminals) and historically some mail agents.

On a directory — the genuinely useful case — setgid changes group inheritance: files created inside get the directory’s group rather than the creator’s primary group, and new subdirectories inherit setgid too. It’s the standard recipe for shared team space:

chgrp devteam /srv/shared
chmod 2775 /srv/shared    # rwxrwxr-x + setgid

Now anything any member creates stays devteam-grouped — no chgrp discipline required. (Default file permissions still come from each member’s umask, so teams usually pair it with umask 002 in their shell profile.)

One edge worth knowing: on Linux, a file that is setgid without group-execute can additionally enable mandatory file locking — a legacy locking semantic that shows as S in ls -l. You’ll meet it in audits more often than you’ll ever need it.

sticky (1000): protect entries in a shared directory

Deleting or renaming a file is a directory operation — it needs write on the directory, and nothing on the file itself. That makes any world-writable directory a free-for-all: anyone can remove anyone else’s files. The sticky bit adds one rule to a writable directory: only the entry’s owner (or root, or the directory owner) may delete or rename it.

chmod +t dir or chmod 1777 dir. /tmp and /var/tmp are the canonical examples — drwxrwxrwt — and the same pattern applies to any shared upload, cache or drop directory you create.

Two honest footnotes:

  • On a regular file it does nothing on modern systems. (Pre-paging Unix kept the program’s text segment in swap — “sticky” — for fast re-launch. That’s why it’s named that; the meaning migrated to directories decades ago.)
  • Symbolic support varies. GNU/Linux treats sticky as part of the o class: o+t sets it, o= clears it. macOS/BSD only applies t through +t, a+t or -to+t is silently ignored there. When writing portable commands, use +t/a+t; this site’s calculator emits the portable form while following GNU rules internally.

Quick reference

octal symbolic on a file on a directory
4xxx u+s / u-s run with owner’s euid (scripts ignored) no standard effect
2xxx g+s / g-s run with group’s egid; S+no-x may enable mandatory locking new files inherit the dir’s group; subdirs inherit setgid
1xxx +t / o+t (GNU), -t nothing (obsolete “save text”) only owners can delete/rename their entries

Set them with the calculator’s special row — watch the octal grow a fourth digit and the ls -l string sprout s/S/t/T exactly as your shell would render it.

Frequently asked questions

What does chmod 4755 do?

Sets the setuid bit plus rwxr-xr-x: the program runs with the file owner's privileges no matter who launches it. That's how /usr/bin/passwd (owned by root) lets a normal user edit the password file. In ls -l it renders as -rwsr-xr-x — the s replaces the owner's x.

Why does ls -l show a capital S or T?

The special bit is set but the execute bit is not. s = setuid/setgid with execute (normal), S = setuid/setgid without execute — on a file that's almost always a mistake, since a setuid program that can't run is just confusing. Same split for t/T on the sticky bit: T means sticky without execute on 'others'.

Is chmod +s on a shell script dangerous?

On Linux it does nothing — the kernel ignores setuid/setgid on interpreted scripts because the interpreter's startup creates a race condition that's been exploited for decades. Where it does work (some Unix variants), a setuid-root script is a classic privilege-escalation vector: environment manipulation, $PATH interception, /tmp races. Use a small setuid wrapper binary or sudo with a narrow rule instead.

What is the sticky bit for on /tmp?

Without it, /tmp is writable by everyone — including deleting other people's files, since deletion is a directory-write operation. Sticky (1777) adds a rule: you can only delete or rename entries you own. That's the entire difference between a shared scratch space and a free-for-all. It also applies to shared upload or cache directories you create yourself.

What does setgid do on a directory?

Two things: new files created inside inherit the directory's group (not the creator's primary group), and new subdirectories inherit the setgid bit too, so the behavior propagates. It's the standard mechanism for shared team directories — chgrp team dir && chmod 2775 dir — so every member's files stay group-accessible regardless of their umask.

Do o+t and u+t work in chmod symbolic mode?

On Linux (GNU chmod), o+t sets sticky and o= clears it — sticky counts as part of the 'other' class. On macOS/BSD it differs: sticky is only applied through +t/a+t/-t, and o+t, o-t are silently ignored. The calculator follows GNU semantics and writes portable commands (+t) that work on both.