---
title: 'Special Permission Bits'
source: 'https://academia.sh/en/courses/introduction-to-linux/special-permission-bits'
course: 'Introduction to Linux'
language: en
updated: '2026-08-17T18:09:57+00:00'
license: 'CC BY-SA 4.0'
---

# Special Permission Bits

The three bits above the nine permission bits; setuid and setgid, which change who a program runs as, group inheritance in directories, and the sticky bit that narrows delete permission.

The users lesson left one detail open: in the permission string of the password-change
program, there was an `s` instead of an `x` at the third position of the owner class.

```
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 72056 May 30  2024 /usr/bin/passwd
```

This lesson explains that letter and its two siblings. Three extra bits solve three separate
problems the nine permission bits cannot, and all three are forms of privilege
escalation — this time embedded in the file's own metadata.

## Four-Digit Notation

The permission field is actually **twelve bits**, not nine. Three extra bits form the fourth
digit from the left in octal notation:

| Bit | Octal | Name |
|---|---|---|
| setuid | 4000 | Set user ID |
| setgid | 2000 | Set group ID |
| sticky | 1000 | Sticky |

The full value can be read with `stat`:

```
$ stat -c '%a %A %n' scripts/summary.sh share
4755 -rwsr-xr-x scripts/summary.sh
3770 drwxrws--T share
```

`4755` means setuid plus `755`; `3770` means setgid plus sticky plus `770`. `chmod` can take a
four-digit value; the symbolic counterparts are `u+s`, `g+s`, and `+t`.

The extra bits do not get their own column; they change the letter at the existing `x`
positions:

| Position | With `x` on | With `x` off |
|---|---|---|
| Owner (setuid) | `s` | `S` |
| Group (setgid) | `s` | `S` |
| Others (sticky) | `t` | `T` |

An uppercase letter reports that the extra bit is on but the execute bit beneath it is off.
This is usually a sign of misconfiguration; the `drwxrws--T` output above, though, is an
intended state — the "others" class has been given no permission at all on this directory.

## setuid: Changing Who the Runner Is

Normally a program runs with the identity of the user who runs it. If the **setuid** bit is on
for an executable file, it runs with its **owner's** identity, not the runner's.

The password-change program is marked this way for exactly this reason. The program is owned
by root and has the setuid bit on; when an ordinary user runs it, the process runs with root
privilege and can update the password file, which only root can write to. The user does not
access the file directly; they access a controlled program that does.

The model follows the same principle as the policy in the privilege escalation lesson, but
keeps the privilege not in an externally defined policy but in the file's own metadata. Two
consequences follow.

**setuid programs are an attack surface.** Every bug in such a program can turn into privilege
gain. For this reason setuid programs are kept few, do narrow work, and scrutinize their
input closely. The list of setuid files on a system can be pulled with `find`; the criterion
option carries the name `-perm` and is a standard step in routine audits.

**It is ignored in shell scripts.** The kernel does not apply this bit to files run through an
interpreter:

```
$ printf '#!/bin/sh\nid -un\n' > /tmp/identity.sh
$ chmod 4755 /tmp/identity.sh
$ ls -l /tmp/identity.sh
-rwsr-xr-x 1 student student 17 Jul 26 19:31 /tmp/identity.sh
```

The result does not change when another user runs it:

```
$ id -un
backup
$ /tmp/identity.sh
backup
```

Although the bit appears on, the process ran with the `backup` identity. The reason is a race
condition: in the time between the kernel opening the file and running the interpreter, the
file could be changed, and the privileged interpreter could end up running a different script.
This door is closed by ignoring the bit.

## setgid: On Files and On Directories

On executable files, the **setgid** bit is setuid's group counterpart: the process runs with
the file's group, not the runner's.

On directories it carries an entirely different and far more commonly used meaning: **new
files created in the directory take the directory's group, not the creator's primary group.**

This was exactly the problem left open in the ownership lesson. The tree's group had been
changed, but new files still formed with the user's primary group.

```
$ mkdir -p share
$ chgrp project share
$ chmod 770 share
$ ls -ld share
drwxrwx--- 2 student project 4096 Jul 26 19:30 share
$ touch share/test-1.csv
$ ls -l share
total 0
-rw-r--r-- 1 student student 0 Jul 26 19:30 test-1.csv
```

Even though the directory belongs to the `project` group, the file created inside it takes on
the `student` group; group members cannot write to it. Once the setgid bit is added, the
behavior changes:

```
$ chmod g+s share
$ ls -ld share
drwxrws--- 2 student project 4096 Jul 26 19:30 share
$ touch share/test-2.csv
$ ls -l share
total 0
-rw-r--r-- 1 student student 0 Jul 26 19:30 test-1.csv
-rw-r--r-- 1 student project 0 Jul 26 19:30 test-2.csv
```

The file created before the bit kept its old group; the one created after took the directory's
group. The bit is also **copied to newly created subdirectories**, so the inheritance persists
across the whole tree.

For group sharing to work, three settings need to be made together: the directory's group,
group write permission, and the setgid bit. If any one of the three is missing, sharing does
not work, and the symptom looks different each time.

For new files to also get group write permission, the mask needs adjusting too; the `022` mask
from the permission bits lesson turns off group write. When working in shared directories, the
mask is set to `002`.

## The Path Must Be Passable

Sharing does not end with directory permissions. The rule from the path resolution lesson
comes into play here: reaching a shared directory requires **pass-through permission at every
directory along the path**.

```
$ chgrp project ~
$ chmod 710 ~
$ ls -ld ~
drwx--x--- 5 student project 4096 Jul 26 19:13 /home/student
```

A value of `710` gives the owner full access and the group only pass-through permission. Group
members cannot **list** the home directory's contents, but can pass through it:

```
$ id -un
backup
$ ls /home/student
ls: cannot open directory '/home/student': Permission denied
$ ls /home/student/project/share
test-1.csv  test-2.csv
```

The reverse of the "read without pass-through" example from the permission bits lesson has
become a real configuration here: the home directory's contents stay hidden while a
subdirectory whose name is known can be shared.

## The Sticky Bit

The shared directory now works, but the gap left open in the permission bits lesson is still
open: a user with write permission on the directory can delete **any** file inside it.

```
$ id -un
backup
$ ls -l
total 0
-rw-rw-r-- 1 student project 0 Jul 26 19:31 test-1.csv
-rw-rw-r-- 1 student project 0 Jul 26 19:31 test-2.csv
$ rm test-1.csv
$ ls -l
total 0
-rw-rw-r-- 1 student project 0 Jul 26 19:31 test-2.csv
```

The `backup` user deleted a file they did not own. The definition from the deletion lesson
explains this: deleting removes a directory entry, and the permission checked is the
directory's write permission.

The **sticky bit** narrows this rule. In a directory with the bit on, only three parties can
remove an entry: the file's owner, the directory's owner, and root.

```
$ chmod +t share
$ ls -ld share
drwxrws--T 2 student project 4096 Jul 26 19:31 share
```

The same user tries the same operation again:

```
$ rm test-2.csv
rm: cannot remove 'test-2.csv': Operation not permitted
$ touch backup-note.csv
$ ls -l
total 0
-rw-rw-r-- 1 student project 0 Jul 26 19:31 test-2.csv
-rw-r--r-- 1 backup  project 0 Jul 26 19:31 backup-note.csv
$ rm backup-note.csv
$ ls -l
total 0
-rw-rw-r-- 1 student project 0 Jul 26 19:31 test-2.csv
```

Deleting someone else's file is blocked; deleting a file the user created is not blocked. Write
permission has not disappeared either — new files can still be added to the directory. The bit
narrows only **deletion and renaming**.

This is the standard configuration for temporary directories on a system:

```
$ ls -ld /tmp
drwxrwxrwt 1 root root 4096 Jul 26 19:24 /tmp
```

The `rwxrwxrwt` string says: everyone can write, but everyone can only delete their own file.
Without the sticky bit, the temporary directory would be a space where everyone could delete
everyone else's files.

## Summary

- The permission field is twelve bits; three extra bits form the fourth octal digit.
- The extra bits do not get their own column, they change the letter at the `x` positions;
  an uppercase letter reports the execute bit beneath it is off.
- A setuid-marked executable runs with its owner's identity, not the runner's; it is ignored
  in shell scripts because of a race condition.
- In directories, setgid makes new files take the directory's group and is copied to
  subdirectories; group sharing needs the group, write permission, and this bit together.
- Reaching a shared directory requires pass-through permission at every directory along the
  path; a value of `710` grants pass-through without listing.
- The sticky bit lets only the file's owner, the directory's owner, and root remove an entry
  in a directory; it is the standard configuration for temporary directories.

## Next Step

The identity, permission, and privilege model is complete; the project tree can now be safely
shared with a group. One last layer about the system itself remains: how did the tools used to
work in this tree get onto the system, how are they updated, and how are they removed? The
next topic opens with the concept of a package manager and closes the course with the text
editors needed to work in the tree.
