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.

You need

  • A Linux system with sudo access

Do first

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.