Skip to content
Linux Administration
Lab 9 of 27·30mBeginner

Day 04: umask, setuid and the sticky bit

Work out why new files get the permissions they do, then examine the three special bits and where each one is legitimately used.

Nobody sets 644 on a new file, yet that is what it gets. Something is subtracting bits, and knowing what closes a whole category of "why is this file group-writable" questions.

1. Find out what is subtracting the bits

mkdir -p ~/labs/special && cd ~/labs/special
umask
touch a.txt
mkdir a.dir
stat -c '%a %n' a.txt a.dir

Files are created requesting 666 and directories 777. The umask is subtracted. With a umask of 022 you get 644 and 755 — the values from Day 01, now explained.

Directories keep x because they were asking for it; files never get x from creation at all, which is why a fresh script needs chmod +x.

Verify

umask # 0022 on most systems, 0002 on some distributions

2. Change it and watch the result move

umask 077
touch private.txt
mkdir private.dir
stat -c '%a %n' private.txt private.dir
umask 022

077 gives 600 and 700 — owner only. This is the umask you want in a script that writes credentials, and setting it is more reliable than a chmod afterwards, because there is no window where the file exists with looser permissions.

Verify

stat -c '%a' private.txt # 600

3. Look at a real setuid binary

ls -l /usr/bin/passwd
stat -c '%A %U %n' /usr/bin/passwd

The owner's x shows as s: setuid. The binary runs as its owner — root — no matter who launched it. That is how an ordinary user can change their own password, an operation that writes to /etc/shadow.

Find every one on the system:

find /usr/bin /usr/sbin -perm -4000 -type f 2>/dev/null

That list should be short and boring. A setuid binary you do not recognise is a genuine finding, because it is a standing offer to run someone's code as root.

Verify

find /usr/bin -perm -4000 -type f 2>/dev/null | wc -l # a small number, typically under 15

4. Prove setuid is ignored on scripts

printf '#!/bin/bash\nid -u\n' > whoami.sh
chmod 4755 whoami.sh
ls -l whoami.sh
./whoami.sh

The s bit is set, and it does nothing — the script prints your uid, not root's. Linux deliberately ignores setuid on interpreted scripts, because the window between the kernel reading #! and the interpreter opening the file is exploitable. If you find advice telling you to setuid a shell script, the advice is from a system where it silently did not work.

Verify

./whoami.sh # your own uid, not 0

5. Understand the sticky bit through /tmp

ls -ld /tmp

Others' x shows as t: the sticky bit. /tmp is 1777 — anyone may create files there. Without sticky, "anyone may write to the directory" would also mean anyone may delete anyone else's files, since deletion is a write to the directory. Sticky narrows that to: you may only remove entries you own.

sudo useradd -m -s /bin/bash tempuser
sudo -u tempuser touch /tmp/owned-by-tempuser
ls -l /tmp/owned-by-tempuser
rm /tmp/owned-by-tempuser

The rm fails despite /tmp being world-writable. That is sticky doing its job.

Verify

rm /tmp/owned-by-tempuser 2>&1 | head -n 1 # rm: cannot remove '/tmp/owned-by-tempuser': Operation not permitted

Clean up

sudo rm -f /tmp/owned-by-tempuser
sudo userdel -r tempuser
cd ~ && rm -rf ~/labs/special

Where this goes next

Four days of files, users and bits. Tomorrow is a challenge with no steps: a directory nobody can get into, and you have to work out which of the four things you have learned is wrong.