Linux SUID, SGID, and Sticky Bit: Master Special Permissions for System Security

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Quick Start: Spot and Set Special Permissions in 5 Minutes

You’re browsing a directory with ls -l and notice something odd — an s where you’d normally see an x, or a t hanging at the end of a permission string. These are Linux’s special permission bits: SUID, SGID, and Sticky Bit. Most sysadmins recognize the symbols. Far fewer understand what’s actually happening under the hood when those bits fire.

Here’s how to find them immediately:

# SUID — notice the 's' in the owner execute position
ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root 68208 Apr 16  2024 /usr/bin/passwd

# Find all SUID files on the system
find / -perm -4000 -type f 2>/dev/null

# Find all SGID files
find / -perm -2000 -type f 2>/dev/null

# Find directories with Sticky Bit
find / -perm -1000 -type d 2>/dev/null

The numeric values are straightforward:

  • SUID = 4 — prepend to permissions, e.g. chmod 4755
  • SGID = 2 — e.g. chmod 2755
  • Sticky Bit = 1 — e.g. chmod 1777

Symbolic notation works too:

# Set SUID on an executable
chmod u+s /path/to/binary

# Set SGID on a shared directory
chmod g+s /shared/project

# Set Sticky Bit on a writable directory
chmod +t /shared/uploads

Deep Dive: What Each Bit Actually Does Under the Hood

SUID — Temporarily Become the File Owner

Here’s the classic puzzle: a regular user can run passwd and change their password, but /etc/shadow is owned by root and unreadable by everyone else. How does that work?

ls -l /etc/shadow
# ---------- 1 root shadow 1234 Jun  1 10:00 /etc/shadow

ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root 68208 Apr 16 2024 /usr/bin/passwd

That s in passwd‘s owner execute slot is SUID. When this binary runs, the kernel temporarily sets the process’s effective UID to the file’s owner — root in this case — instead of the calling user’s UID. The program runs with elevated privileges for as long as it’s executing. When it exits, those privileges vanish.

Security implication: every SUID root binary is a potential privilege escalation target. One exploitable bug — a buffer overflow, a path injection — and an attacker walks away with a root shell. Keep your production SUID list short, and know exactly why each entry is there.

SGID — Group Inheritance That Actually Solves Team Problems

SGID behaves differently depending on whether it targets a file or a directory.

On executables: Same concept as SUID, but uses the file’s group rather than owner. The process’s effective GID becomes the file’s group.

ls -l /usr/bin/write
# -rwxr-sr-x 1 root tty 14328 Jan 20 2024 /usr/bin/write
# 's' in group execute position = SGID

On directories: The directory case is where SGID actually earns its place in real deployments. Any file created inside a SGID directory automatically inherits the directory’s group, regardless of what primary group the creator belongs to.

# Set up a shared project directory for the devteam group
sudo groupadd devteam
sudo mkdir /projects/webapp
sudo chown :devteam /projects/webapp
sudo chmod 2775 /projects/webapp

ls -ld /projects/webapp
# drwxrwsr-x 2 root devteam 4096 Jun  2 09:00 /projects/webapp

# Any file created here now belongs to devteam automatically
touch /projects/webapp/app.py
ls -l /projects/webapp/app.py
# -rw-rw-r-- 1 youruser devteam 0 Jun  2 09:01 app.py

Without SGID, every developer creates files with their own primary group. Nobody else can write to them without a manual chmod after every single file creation. SGID on directories eliminates that friction entirely.

Sticky Bit — Protecting Shared Writable Directories

The problem Sticky Bit solves: if /tmp is world-writable (which it must be), what stops user bob from deleting alice‘s temp files?

ls -ld /tmp
# drwxrwxrwt 18 root root 4096 Jun  2 09:30 /tmp
# The 't' at the end — Sticky Bit

With Sticky Bit set, write permission on the directory no longer means you can delete other people’s files. Only the file owner, the directory owner, or root can remove a file inside that directory.

# alice creates a temp file
touch /tmp/alice_session.sock

# bob tries to remove it — denied
rm /tmp/alice_session.sock
# rm: cannot remove '/tmp/alice_session.sock': Operation not permitted

Advanced Usage: Real Production Scenarios

Combining SGID and Sticky Bit for Team Directories

We ran this exact setup on a production Ubuntu 22.04 server. The result: zero permission-related tickets from developers for months. Nobody needed to remember chown or chmod after creating files — group inheritance and deletion protection just worked.

# SGID(2) + Sticky(1) = 3 — combine them
sudo mkdir /var/shared/team-data
sudo chown root:devteam /var/shared/team-data
sudo chmod 3775 /var/shared/team-data

ls -ld /var/shared/team-data
# drwxrwsr-t 2 root devteam 4096 Jun  2 10:00 /var/shared/team-data
# 's' = SGID (group inherits), 't' = Sticky Bit (owners only can delete)

SUID on Custom Admin Binaries — The Right Way

You might want non-root users to restart a specific service. SUID seems like the answer — but there’s a catch: Linux intentionally ignores SUID on shell scripts. You need a compiled C wrapper.

# SUID on shell scripts is silently ignored
chmod u+s /usr/local/bin/restart-nginx.sh  # Does nothing useful

# Correct approach: a minimal C wrapper
cat << 'EOF' > /tmp/restart-nginx.c
#include <unistd.h>
int main() {
    setuid(0);
    execl("/bin/systemctl", "systemctl", "restart", "nginx", NULL);
    return 1;
}
EOF

gcc -o /usr/local/bin/restart-nginx /tmp/restart-nginx.c
chown root:webadmin /usr/local/bin/restart-nginx
chmod 4750 /usr/local/bin/restart-nginx
# Only 'webadmin' group members can execute it, runs as root

Honestly, a targeted sudo rule is cleaner than any custom SUID binary in most situations. Use SUID sparingly — the fewer SUID files on your system, the smaller the attack surface.

Baseline and Diff for Security Audits

# Create a baseline before any system changes
find / -perm /6000 -type f 2>/dev/null | sort > /root/suid_baseline.txt

# After installing packages or patches, compare
find / -perm /6000 -type f 2>/dev/null | sort > /root/suid_current.txt
diff /root/suid_baseline.txt /root/suid_current.txt
# Any new lines = new SUID/SGID binaries added to the system

Run this after every significant package update. A new SUID binary showing up unexpectedly is worth investigating immediately — don’t assume the package manager put it there intentionally.

Practical Tips: Hardening Your System

Strip Unnecessary SUID/SGID Bits

Servers don’t need most of the SUID binaries that ship with a desktop-oriented distribution. Review and strip what isn’t needed:

# Remove SUID from a file
chmod u-s /usr/bin/at

# Remove SGID
chmod g-s /usr/bin/newgrp

# Common review candidates on headless servers:
ls -l /usr/bin/at       # Batch job scheduler
ls -l /usr/bin/newgrp   # Switch groups
ls -l /usr/bin/chsh     # Change login shell
ls -l /usr/bin/chfn     # Change user info

Use nosuid Mount Options on Data Partitions

Any partition that doesn’t need SUID executables — upload directories, /tmp, user home partitions — can use the nosuid mount option. It makes SUID and SGID bits on that partition completely inert, even if someone manages to plant a malicious file there:

# /etc/fstab
/dev/sdb1  /data   ext4  defaults,nosuid,noexec  0  2
/dev/sdc1  /home   ext4  defaults,nosuid         0  2

# Remount live without a reboot
sudo mount -o remount,nosuid /data

Quick Reference: When to Use Each Bit

  • SUID on executables: Only when a program genuinely must run as its owner. Every SUID root binary is a potential privilege escalation vector.
  • SGID on directories: Shared team directories where consistent group ownership matters. Safe, practical, and commonly useful.
  • Sticky Bit on directories: Any world-writable or group-writable shared directory. Standard for /tmp, upload dirs, and scratch spaces.
  • SUID on shell scripts: Linux ignores it — use sudo rules or a compiled C wrapper instead.

Doing a pentest or working through a CTF? Finding find, vim, cp, or bash with SUID root is essentially a free privilege escalation — find -exec /bin/sh \; or vim‘s built-in shell escape gets you there in seconds. On production systems, that’s the misconfiguration to catch before anyone else does.

Share: