Understanding setuid, setgid, and the Sticky Bit on Fedora

Setuid, setgid, and sticky bits control execution privileges and file deletion rules on Linux using chmod commands.

The scenario: permissions that change who you are

You run passwd to change your password. The command succeeds even though you are not root. You check the permissions with ls -l and see -rwsr-xr-x. That s in the user execute position is not a typo. It tells the kernel to run this binary with the privileges of the file owner, not the user who typed the command.

Now you want to replicate that behavior for a custom script that mounts a drive, or you are debugging a shared directory where users keep deleting each other's files. You try chmod u+s script.sh and nothing happens. You try chmod +t /shared and get confused by the error when you try to delete a file. You need to understand setuid, setgid, and the sticky bit. These are not just permission flags. They change the security context of execution and file creation.

What the kernel actually does

Standard Linux permissions check who you are before letting you access a resource. The kernel compares your user ID and group ID against the file's owner and group. Special permission bits modify that check. They can change who you become during execution, or change how new files inherit attributes, or restrict deletion in a shared space.

Think of standard permissions as a badge check at a door. Special bits are like handing you a temporary master key for one action, forcing you to wear a team jersey when you enter a room, or posting a rule that only the creator can remove items from a bin.

Setuid runs an executable as the file owner. Setgid runs an executable as the file group, or forces new files in a directory to inherit the directory's group. The sticky bit prevents users from deleting files they do not own, even if they have write access to the directory.

Setuid: temporary root privileges

Setuid stands for "set user ID." When you set this bit on an executable, the process runs with the effective user ID of the file owner. If the file is owned by root, the process runs as root. This is how passwd, ping, and sudo work. They need privileges you do not have, so the kernel grants them temporarily.

Here is how to set the setuid bit on a binary.

# Create a test binary. Scripts are ignored by setuid on modern kernels.
echo '#include <stdio.h>\nint main() { printf("UID: %d\\n", getuid()); }' > test.c
gcc test.c -o test_binary
chown root:root test_binary
chmod u+s test_binary
# WHY: Sets the setuid bit. The binary will run as root regardless of who executes it.

Run ls -l to verify. The output shows s in the user execute position. If the execute bit is not set for the owner, you see a capital S. A capital S means the setuid bit is set, but the file cannot be executed. This is a common configuration error.

ls -l test_binary
# Output: -rwsr-xr-x 1 root root 16000 Jan 1 12:00 test_binary
# WHY: The 's' confirms setuid is active and the owner has execute permission.

Setuid is a massive security risk. If a user can write to a setuid binary, they can modify it and gain root access. Fedora blocks setuid on scripts by default. The kernel parameter fs.protected_regular prevents the setuid bit from working on interpreted files. This stops a class of race condition attacks where an attacker swaps the script content between the permission check and execution.

sysctl fs.protected_regular
# Output: fs.protected_regular = 2
# WHY: Value 2 disables setuid/setgid on scripts. You must compile binaries to use setuid.

Audit your system regularly. Unnecessary setuid binaries are backdoors waiting to be exploited.

Run find to list all setuid and setgid files. Check every result. If you see a setuid binary in /tmp or a user home directory, investigate immediately.

sudo find / -perm /6000 -type f -ls 2>/dev/null
# WHY: Finds files with setuid (4000) or setgid (2000) bits. The -ls flag shows detailed output.
# 2>/dev/null suppresses permission denied noise from directories you cannot read.

Audit your setuid binaries weekly. A rogue binary is a backdoor waiting to happen.

Setgid: group inheritance and execution

Setgid stands for "set group ID." It has two distinct behaviors depending on whether it is applied to a file or a directory.

On an executable file, setgid runs the process with the effective group ID of the file's group owner. This is rare. Most tools use setuid for privilege escalation.

On a directory, setgid forces new files and subdirectories created inside to inherit the directory's group, not the user's primary group. This is the standard way to set up shared workspaces. Without setgid, a user in the developers group creates a file that belongs to their personal group, breaking collaboration.

Here is how to configure a shared directory with setgid.

mkdir /srv/project
chown :developers /srv/project
chmod 2770 /srv/project
# WHY: 2 sets the setgid bit. 770 gives owner and group full access.
# New files inherit the 'developers' group automatically.

Users in the developers group can now create files, and those files will belong to the developers group. This works recursively. Subdirectories created inside also inherit the setgid bit, so the behavior persists deeper in the tree.

Check the directory permissions to confirm.

ls -ld /srv/project
# Output: drwxrws--- 2 root developers 4096 Jan 1 12:00 /srv/project
# WHY: The 's' in the group execute position confirms setgid is active.

If the group execute bit is missing, you see a capital S. The setgid bit is set, but the group cannot execute or traverse the directory. This breaks the inheritance mechanism for some tools. Ensure the group has at least execute permission on the directory.

Use setgid on directories when a team needs to collaborate and new files must automatically belong to a shared group.

The sticky bit: shared directories without chaos

The sticky bit restricts deletion and renaming of files within a directory. When set on a directory, only the file owner, the directory owner, or root can delete or rename files. Other users can create new files if they have write access, but they cannot touch files they do not own.

This is essential for world-writable directories like /tmp. Without the sticky bit, any user could delete any other user's temporary files.

Here is how to set the sticky bit.

chmod +t /tmp
# WHY: Adds the sticky bit. Users can create files but cannot delete files owned by others.

Verify the change with ls -ld. The output shows a t in the other execute position.

ls -ld /tmp
# Output: drwxrwxrwt 10 root root 4096 Jan 1 12:00 /tmp
# WHY: The 't' confirms the sticky bit is active.

If the other execute bit is missing, you see a capital T. The sticky bit is set, but others cannot traverse the directory. This is unusual for shared directories.

Try to delete a file you do not own in a sticky directory. The kernel rejects the operation.

rm /tmp/other_user_file
rm: cannot remove '/tmp/other_user_file': Operation not permitted

This error is expected. The sticky bit protects files from unauthorized deletion.

Use the sticky bit on world-writable directories when multiple users need to create files but must not delete each other's work.

Octal notation and the capital S trap

You can set these bits using symbolic notation like u+s or octal notation. Octal notation prepends a digit to the standard three-digit permission code. The special bits use the thousands place.

The value 4 sets setuid. The value 2 sets setgid. The value 1 sets the sticky bit. You can combine them.

  • 4755 sets setuid and permissions rwxr-xr-x.
  • 2775 sets setgid and permissions rwxrwxr-x.
  • 1777 sets the sticky bit and permissions rwxrwxrwx.
  • 7777 sets all three bits. This is almost never what you want.

Here is how to apply combined octal permissions.

chmod 4755 /usr/local/bin/mount_helper
# WHY: Sets setuid (4) and permissions 755. The binary runs as root with standard execute rights.
chmod 2770 /srv/shared
# WHY: Sets setgid (2) and permissions 770. Group inheritance with no access for others.
chmod 1777 /var/tmp/upload
# WHY: Sets sticky bit (1) and permissions 777. World-writable with deletion protection.

The capital S and T traps catch many administrators. If you see -rwsr-xr-x, the setuid bit is active and the owner can execute. If you see -rwSr-xr-x, the setuid bit is set, but the owner cannot execute. The kernel ignores setuid if the execute bit is missing. The file looks special, but it behaves normally.

Check the execute bits whenever you see a capital letter in the permission string. A capital letter means the special bit is configured but ineffective.

Check the execute bit. A capital S means the setuid bit is set but the file cannot run.

Common pitfalls and error messages

Setuid scripts fail silently on Fedora. You run chmod u+s script.sh, check ls -l, and see the s. You run the script, and it runs as your user, not root. The kernel ignores the bit because fs.protected_regular is enabled. You must compile the code into a binary.

SELinux blocks unauthorized setuid transitions. If you set setuid on a binary that SELinux does not expect to run as root, the access is denied. You see an error in the journal.

type=AVC msg=audit(1704067200.123:456): avc:  denied  { setuid } for  pid=1234 comm="my_script" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=process permissive=0

Read the denial with journalctl -t setroubleshoot. The summary explains why SELinux blocked the action. Do not disable SELinux to fix this. Adjust the policy or use sudo with a proper configuration file instead.

World-writable setuid binaries are critical vulnerabilities. If you see -rwsrwxrwx, the binary is owned by root, runs as root, and can be modified by anyone. This is a root compromise. Remove the setuid bit immediately and investigate how the permissions changed.

chmod u-s /path/to/compromised_binary
# WHY: Removes the setuid bit to stop immediate exploitation.

Run find to audit permissions. Trust nothing you did not install yourself.

When to use each bit

Use setuid when a specific binary must perform a privileged action that the user cannot do, and you have audited the code for vulnerabilities.

Use setgid on directories when a team needs to collaborate and new files must automatically belong to a shared group.

Use the sticky bit on world-writable directories when multiple users need to create files but must not delete each other's work.

Avoid setuid on scripts entirely. Modern kernels block this for security reasons. Use sudo with a targeted configuration instead.

Avoid setuid on binaries that accept user input without strict validation. A buffer overflow in a setuid root binary gives the attacker the system.

Where to go next