| Tested on | RHEL 10.2 |
|---|---|
| Package | coreutils (chmod, ls, find) |
| Applies to | RHEL, Rocky Linux, AlmaLinux, CentOS Stream, Fedora, Ubuntu, Debian, and other Linux systems with POSIX permissions |
| Privilege | Normal user to inspect setuid binaries; sudo to change modes on system paths |
| Scope | Setuid on executable files: chmod u+s, octal 4 prefix, s vs S, passwd example, find, and nosuid mounts. Does not cover capabilities, SELinux, or writing custom setuid programs. |
| Related guides | Linux file permissions Setgid in Linux Sticky bit in Linux chmod recursive find command |
Setuid on an executable means the program runs with the file owner's UID,
not the UID of the person who launched it. You see it on /usr/bin/passwd as
the s in -rwsr-xr-x. That is how a normal user can update their own
password without having direct permission to read or modify /etc/shadow.
Quick Reference: Setuid Commands
| Task | Command |
|---|---|
| Set setuid (symbolic) | chmod u+s file |
Set setuid with mode 755 |
chmod 4755 file |
| Remove setuid | chmod u-s file or drop the 4 digit in octal |
| List setuid files | find /path -type f -perm -4000 |
| Inspect mode | ls -l file (look for s or S in user execute) |
1. What Is Setuid in Linux?
Regular executables run as you. The kernel sets the process effective UID from your login session. Setuid flips that rule for one file: whoever runs it temporarily inherits the owner's UID for that process.
That matters when a trusted program must touch root-only resources on behalf
of an unprivileged user. passwd must update /etc/shadow, which normal
users cannot modify directly. Without setuid, every user would need direct
shadow access or a setuid helper could not exist.
Setuid applies to executable files, not directories. On Linux, setuid on a directory is not a supported access-control pattern the way setgid on a directory is.
Root and the "others" permission class
Setuid changes the process effective UID when someone who is not the file owner runs the executable. If you are already root, setuid on a root-owned binary does not grant anything new—you already pass DAC checks.
For normal users, setuid is the elevation path: passwd runs with UID 0 long
enough to update shadow, even though the shell session is still your account.
The s is stored in the user (owner) execute slot (chmod u+s), not in
the others column. To run the program at all, your user still needs execute
through owner, group, or others permissions. passwd is 755, so the
others triplet is r-x and any user may invoke it. Without x for your
access class, the kernel refuses to start the binary regardless of setuid.
2. The borrowed badge: why setuid exists
Picture a secure office building. Most employees have a blue badge that opens the lobby and their own desk. The server room needs a red badge. You do not hand every employee a permanent red badge just so they can change their voicemail PIN.
Instead, the building runs one approved kiosk program owned by facilities (red badge baked in). You walk up as yourself (blue badge), the kiosk checks your identity, performs the one task you are allowed to request, and logs the change. You never keep the red badge when you leave.
Setuid is that kiosk. The file is owned by root (red badge). You run it as your normal user. For the lifetime of that process, the kernel treats the effective UID as root so the program can reach protected files, but only along the code path the binary implements.
When setuid helps
- Small, audited system utilities (
passwd,mount,su) that must cross a privilege boundary safely - Vendor packages that ship a fixed helper instead of handing users root shells
When you should not add your own
- Random shell scripts with
chmod u+s(any local user who can edit the script owns your escalation path) - Daemons that should run as a dedicated service account with sudo or systemd
User=instead - Files on
nosuidmounts, where the kernel ignores setuid bits entirely
If you need persistent root access for an app, use sudo rules, a service unit,
or Polkit. Do not sprinkle u+s on homemade binaries.
3. Why /usr/bin/passwd Uses Setuid
passwd is the textbook setuid binary. It is owned by root, executable by
everyone, and marked setuid so the process can update shadow entries:
ls -l /usr/bin/passwd-rwsr-xr-x. 1 root root 91424 Feb 23 05:30 /usr/bin/passwdThe s in the user execute column means setuid is on and execute is set.
Octal mode 4755 breaks down as 4 (setuid) plus 755 (owner read/write/exec,
group/other read/exec).
As a normal user you still cannot read /etc/shadow directly:
cat /etc/shadowcat: /etc/shadow: Permission deniedRunning /usr/bin/passwd is different. The binary runs with root's effective
UID long enough to validate your old password and rewrite your shadow line.
You never get a root shell; you get one controlled operation.
4. Set Setuid with chmod u+s
For a safe permissions-only demonstration, create a regular script and inspect
the mode bit. Linux ignores setuid and setgid bits when executing scripts, so
this example demonstrates chmod and ls output only — it does not demonstrate
privilege elevation:
printf '#!/bin/sh\necho setuid demo\n' > /tmp/suid-demo.shGive the file execute permission first:
chmod u+x /tmp/suid-demo.shThen layer setuid on top:
chmod u+s /tmp/suid-demo.shCheck the user execute slot for s:
ls -l /tmp/suid-demo.sh-rwsr--r--. 1 user user 27 Aug 15 19:48 /tmp/suid-demo.shRemove the demo file when you are done. Do not leave setuid bits on scripts you can edit; even compiled setuid binaries belong only in audited packages.
5. Set Setuid with Octal Mode 4755
Octal mode uses a fourth leading digit for special bits. 4 is setuid, 2 is
setgid, and 1 is sticky (see sticky bit).
Apply setuid together with mode 755:
chmod 4755 /tmp/suid-demo.shOctal 4755 sets the full mode: 4 (setuid) plus 755 (rwxr-xr-x). Confirm
the listing:
ls -l /tmp/suid-demo.sh-rwsr-xr-x. 1 user user 17 Aug 15 20:22 /tmp/suid-demo.shUse octal when you set the full mode in one command. If the file already has the
right rwx bits, chmod u+s is safer because it cannot accidentally widen
group or other permissions.
6. Lowercase s vs Uppercase S
ls encodes setuid in the user execute position:
- lowercase
s— setuid and user execute are both on - uppercase
S— setuid is on but user execute is off (unusual and not runnable)
Create setuid without execute to see uppercase S:
chmod 4644 /tmp/suid-demo.shls should show S where user execute would be:
ls -l /tmp/suid-demo.sh-rwSr--r--. 1 user user 27 Aug 15 19:48 /tmp/suid-demo.shAdd execute back and the letter drops to lowercase s:
chmod u+x /tmp/suid-demo.shThe mode line should read -rws again:
ls -l /tmp/suid-demo.sh-rwsr--r--. 1 user user 27 Aug 15 19:48 /tmp/suid-demo.sh7. Remove Setuid
Drop the bit with symbolic mode:
chmod u-s /tmp/suid-demo.shOr set the full mode without the setuid digit. chmod 755 replaces the entire
permission field:
chmod 755 /tmp/suid-demo.shConfirm the s is gone:
ls -l /tmp/suid-demo.sh-rwxr-xr-x. 1 user user 17 Aug 15 20:22 /tmp/suid-demo.sh8. Find Files with Setuid
Setuid is bit 4000 in octal. find -perm -4000 matches files where all bits
specified by 4000 are set — here, that simply means setuid is present:
find /usr/bin -maxdepth 1 -type f -perm -4000/usr/bin/umount
/usr/bin/mount
/usr/bin/chage
/usr/bin/gpasswd
/usr/bin/newgrpExpect a short list on a minimal install and a longer one on a desktop system. Audit unexpected setuid binaries after package installs or compromise drills.
Mounts with nosuid ignore setuid bits on that filesystem. That is common
on /home NFS exports and removable media.
Setuid vs Setgid and Sticky Bit
| Bit | Where it applies | What changes |
|---|---|---|
setuid (u+s, octal 4) |
executable file | process effective UID becomes file owner |
setgid (g+s, octal 2) |
executable or directory | process GID or new file group — see setgid |
sticky (+t, octal 1) |
directory | delete/rename restricted to owner — see sticky bit |
Only one special bit belongs on a given task. passwd needs setuid, not
sticky. /tmp needs sticky, not setuid.
Summary
Setuid lets a trusted executable run with its owner's UID instead of the
caller's. That is how passwd updates /etc/shadow while normal users
cannot read or modify that file directly.
Set it with chmod u+s or a leading 4 in octal (4755). Lowercase s
means execute is present; uppercase S means setuid without execute. Remove
it with chmod u-s or by dropping the 4 digit. Use find … -perm -4000
to audit setuid files.
Treat setuid as a vendor-curated mechanism, not a shortcut for your own scripts. For shared folders and group ownership, use setgid. For world-writable directories, use sticky bit.
References
man chmodman 7 credentials(saved set-user-ID)- GNU Coreutils chmod documentation

