Skip to content
academia.sh

Lesson 16 / 20

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.

Contents

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.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ Esc navigate · open · close