Linux permissions — exercises with chmod, umask and a shared submissions folder (and the chmod -R that locked me out of my own folder)

I had a data/ folder with the measurements from a lab and I wanted my classmates to be able to read them. I remembered that “644 is read for everyone” and, feeling very sure of myself, typed chmod -R 644 data. The terminal complained (cannot access 'data/measurements.csv') and, when I went to check, not even I could get in: cd data → Permission denied. I had left my own folder without its x. The fix was a single letter, a capital X, and you’ll see it in fragment 2 of “What’s wrong here?”.

In these exercises I no longer hand you the commands: you decide the numbers, the letters and the mask. If you need a refresher, you have the Linux permissions theory and practice, and at the end, the cheat sheet with everything on one page.

How to use this article

  1. Read the statement and write the commands on paper or in a file before trying them.
  2. Try them in a test folder (mkdir ~/permissions-exercises && cd ~/permissions-exercises), never in your home folder or as root.
  3. Compare with the expected output. If it doesn’t match, read the hint before the solution.
  4. Read the solution even if you got it right: each one explains why it’s done that way and what would have failed with the obvious alternative.

Level 1 (basic): three permissions, two notations

In a test folder, create the empty files report.txt and build.sh and the directory data. Then:

  • report.txt: I can read and write it, the group can only read it and others can’t do anything. In octal.
  • build.sh: I can read, write and run it, the group can read and run it and others can’t do anything. In symbolic mode, starting from the permissions it’s born with.
  • data: the group can get in and see what’s there, but not create or delete anything; others, out. In octal.

Finish with a stat that shows all three in octal and in letters. Expected stat output:

640 -rw-r----- report.txt
750 -rwxr-x--- build.sh
750 drwxr-x--- data

build.sh is born with 644 (rw-r--r--). Compare it letter by letter with rwxr-x---: there are two xs to add and one r to remove. It can be done in a single command with commas.

Level 2 (intermediate): the group umask

You want everything you create from now on in your terminal to come out like this: files 640 and directories 750. Choose the umask, set it, show it in octal and in letters, and check it by creating a file minutes.txt and a folder screenshots. Expected output (without the commands):

0027
u=rwx,g=rx,o=
640 -rw-r----- minutes.txt
750 drwxr-x--- screenshots

Think about which bits you have to switch off in 666 to get 640, and check that those same bits take 777 to 750. The umask is what gets removed, not what’s left.

Level 3 (challenge): the submissions folder

The ic2 group needs a submissions folder where everyone drops their file. Requirements:

  1. The owner (sergio) and the group can get in, list and create; others, nothing.
  2. Everything created inside must belong to the ic2 group, whoever creates it.
  3. Nobody can delete another person’s files, even though everyone can write in the folder.

Create it as sergio, put sergio.txt inside, and check from Laura’s terminal that her laura.txt comes out with group ic2, that she can’t delete sergio.txt and that she can delete her own. Finally, check that Pablo can’t list the folder. What you should see:

drwxrws--T 2 sergio ic2 4096 Oct 25 16:49 submissions
-rw-r--r-- 1 laura  ic2 0 Oct 25 16:49 laura.txt
-rw-r--r-- 1 sergio ic2 0 Oct 25 16:49 sergio.txt
rm: cannot remove 'submissions/sergio.txt': Operation not permitted
ls: cannot open directory 'submissions': Permission denied

Requirements 2 and 3 are two special bits. Look up in the theory table which one makes the group be inherited and which one stops you deleting other people’s files, and add them up in the leading digit. (For the Laura and Pablo part you need the test users from the practice.)

What’s wrong here?

Three fragments with a mistake people really make. For each one: read the code, predict what will happen and then read the explanation.

Fragment 1: “I read and write, everyone else reads”

touch report.txt
chmod 466 report.txt               # "I read and write, everyone else reads"... are you sure?
echo "Conclusions" >> report.txt
stat -c '%a %A %n' report.txt

Is the line “Conclusions” added to the report?

This is what happens:

$ touch report.txt
$ chmod 466 report.txt
$ echo "Conclusions" >> report.txt
bash: report.txt: Permission denied
$ stat -c '%a %A %n' report.txt
466 -r--rw-rw- report.txt

The stat explains it: 466 is r--rw-rw-. The first digit is always the owner, so the owner (me) is left with r--, without w, while the group and others have rw-. And no, being in the group doesn’t save me: since I’m the owner, Linux only looks at the first triplet. The intention was “6 for me, 4 for the rest”, that is, 644, but the digits were written the wrong way round.

Writing the octal starting with “everyone else”. The order is fixed: owner, group, others. Always read it out loud before pressing Enter: “six for me, four for the group, four for others”.

The fix:

touch report.txt
chmod 644 report.txt               # the first digit is ALWAYS the owner: 6 = rw-
echo "Conclusions" >> report.txt
stat -c '%a %A %n' report.txt

And its output, with no errors and the permissions we wanted:

$ touch report.txt
$ chmod 644 report.txt
$ echo "Conclusions" >> report.txt
$ stat -c '%a %A %n' report.txt
644 -rw-r--r-- report.txt

If you’re unsure about the order, use symbolic mode, which says who gets what: chmod u=rw,go=r report.txt gives 644 without thinking about positions.

Fragment 2: “so everyone can read it”

mkdir data
touch data/measurements.csv
chmod -R 644 data                  # "so everyone can read it"
ls -l data
cd data

Will you be able to see the folder with ls -l and get in with cd?

This is what happens:

$ mkdir data
$ touch data/measurements.csv
$ chmod -R 644 data
chmod: cannot access 'data/measurements.csv': Permission denied
$ ls -l data
ls: cannot access 'data/measurements.csv': Permission denied
total 0
-????????? ? ? ? ?            ? measurements.csv
$ cd data
bash: cd: data: Permission denied

There are three errors, and all three have the same cause. chmod -R applies 644 to the data folder first and then tries to go down into what’s inside… but the folder no longer has x, so it can’t even reach measurements.csv (first error). ls -l can read the name (r) but can’t look up the file (x), which is why you get -?????????. And cd needs the x. The drawing puts both situations side by side:

The x of a directory With 644 the directory lets you read the names (r) but not enter it or look at the files (no x): ls -l shows question marks and cd fails. With 755 everything works. A directory with 644 next to one with 755 data/ 644 drw-r–r– r read the list of names   x enter and look at each file   cd data → Permission denied   what ls -l shows: -????????? ? ? ? ? ? measurements.csv data/ 755 drwxr-xr-x r read the list of names   x enter and look at each file   cd data → gets in, no error   what ls -l shows: -rw-r–r– … measurements.csv
On a directory, r gives you the names and x lets you through: without x, ls -l can only show question marks.

Using chmod -R with a number when there are folders and files inside. A number can’t tell “get in” from “run”: either you take the x away from the folders, or you give it to every file.

The fix uses capital X:

mkdir data
touch data/measurements.csv
chmod -R u=rwX,go=rX data          # capital X: x only on directories (and on what was already executable)
stat -c '%a %A %n' data data/measurements.csv
cd data

The output, with the folder at 755, the file at 644 and cd with no errors:

$ mkdir data
$ touch data/measurements.csv
$ chmod -R u=rwX,go=rX data
$ stat -c '%a %A %n' data data/measurements.csv
755 drwxr-xr-x data
644 -rw-r--r-- data/measurements.csv
$ cd data

X means “set the x only on directories (and on whatever was already executable for someone)”. So u=rwX,go=rX gives rwx r-x r-x (755) to the folder and rw- r-- r-- (644) to the file in a single command.

chmod -R u=rwX,go=rX folder is the recipe for “let everyone read this whole folder” without breaking anything. Write it in your cheat sheet.

Fragment 3: “I want my files to come out as 644”

umask 644                           # "I want my files to come out as 644"
touch new.txt
stat -c '%a %A %n' new.txt
cat new.txt

With which permissions will new.txt be born?

This is what happens:

$ umask 644
$ touch new.txt
$ stat -c '%a %A %n' new.txt
22 -----w--w- new.txt
$ cat new.txt
cat: new.txt: Permission denied

The umask is what gets removed, not what’s left. 666 without rw-r--r-- (644) leaves only ----w--w-, that is, 022 (stat writes it as 22, without the leading zero). The file is born with no r for the owner, which is why not even I can cat it. The exact opposite of what I wanted.

Putting the permissions you want in the umask. To get 644, the umask is what 666 is missing to get there: 6 − 6 = 0, 6 − 4 = 2, 6 − 4 = 2 → 022.

The fix:

umask 022                           # the mask says what is REMOVED: 666 without 022 = 644
touch new.txt
stat -c '%a %A %n' new.txt
cat new.txt

And now the file is born with 644 and can be read (it’s empty, so cat prints nothing):

$ umask 022
$ touch new.txt
$ stat -c '%a %A %n' new.txt
644 -rw-r--r-- new.txt
$ cat new.txt

If you ever mess up the umask in a terminal, no harm done: it only affects that terminal. Close it and open another one, or type umask 022.

Solutions

Level 1 solution

touch report.txt build.sh
mkdir data
chmod 640 report.txt            # octal: rw- r-- ---
chmod u+x,g+x,o-r build.sh      # symbolic, starting from 644 (rw-r--r--) → rwxr-x---
chmod 750 data                  # the group gets in (x) and lists (r), but cannot create (no w)
stat -c '%a %A %n' report.txt build.sh data

The real output matches the expected one:

$ touch report.txt build.sh
$ mkdir data
$ chmod 640 report.txt
$ chmod u+x,g+x,o-r build.sh
$ chmod 750 data
$ stat -c '%a %A %n' report.txt build.sh data
640 -rw-r----- report.txt
750 -rwxr-x--- build.sh
750 drwxr-x--- data

Why it’s done this way:

  • report.txt in octal: we want exact permissions, and 640 reads directly (6 = 4 + 2 = rw-, 4 = r--, 0 = ---).
  • build.sh in symbolic mode, starting from 644. This is the trace of the u+x,g+x,o-r command, applied from left to right:
PartBeforeAfterMaths
u+x644 rw-r--r--744 rwxr--r--6 + 1 = 7
g+x744754 rwxr-xr--4 + 1 = 5
o-r754750 rwxr-x---4 − 4 = 0
  • data at 750 and not 740: without x the group would see the names but couldn’t get in (fragment 2). And not 770, because w would let them create and delete.

The obvious alternative for build.sh, chmod u+x build.sh, stops at 744: the group couldn’t run it and others could read it.

Level 2 solution

umask 027                # removes w from the group (2) and everything from others (7)
umask                    # check in octal
umask -S                 # and in letters: what IS let through
touch minutes.txt
mkdir screenshots
stat -c '%a %A %n' minutes.txt screenshots

The real output:

$ umask 027
$ umask
0027
$ umask -S
u=rwx,g=rx,o=
$ touch minutes.txt
$ mkdir screenshots
$ stat -c '%a %A %n' minutes.txt screenshots
640 -rw-r----- minutes.txt
750 drwxr-x--- screenshots

Why it’s done this way: we compare box by box what has to be switched off:

OwnerGroupOthers
File requested (666)rw-rw-rw-
What we want (640)rw-r-----
To switch offnothing → 0w → 2everything → 7

The umask is 027. Checking with the directory: 777 without ----w-rwx = rwx r-x --- = 750. Notice that for others we use 7 and not 6: on the file there’s no x to remove, but on the directory there is, and without that 1 folders would come out 751.

The obvious alternative, umask 640, is fragment 3 all over again: 026 files (----w-rw-) that not even the owner can read.

Level 3 solution

# @sergio — Sergio sets up the shared submissions folder
mkdir submissions
chgrp ic2 submissions
chmod 3770 submissions        # 3 = 2 (setgid) + 1 (sticky) · 770 = owner and group everything, others nothing
ls -ld submissions
touch submissions/sergio.txt
# @laura — Laura hands in her file and tries to delete Sergio's
touch submissions/laura.txt
ls -l submissions
rm submissions/sergio.txt
rm submissions/laura.txt
ls submissions
# @pablo — Pablo is not in the group
ls submissions

The real output:

sergio$ mkdir submissions
sergio$ chgrp ic2 submissions
sergio$ chmod 3770 submissions
sergio$ ls -ld submissions
drwxrws--T 2 sergio ic2 4096 Oct 25 16:49 submissions
sergio$ touch submissions/sergio.txt
laura$ touch submissions/laura.txt
laura$ ls -l submissions
total 0
-rw-r--r-- 1 laura  ic2 0 Oct 25 16:49 laura.txt
-rw-r--r-- 1 sergio ic2 0 Oct 25 16:49 sergio.txt
laura$ rm submissions/sergio.txt
rm: cannot remove 'submissions/sergio.txt': Operation not permitted
laura$ rm submissions/laura.txt
laura$ ls submissions
sergio.txt
pablo$ ls submissions
ls: cannot open directory 'submissions': Permission denied

Why it’s done this way: the number 3770 has two parts:

DigitValueMeaning
3 = 2 + 1setgid + stickyinherit the group and each user deletes only their own
7rwxowner: everything
7rwxgroup: get in, list and create
0---others: nothing

The drawing puts the two special bits together with what they cause:

The submissions folder with 3770 The submissions folder ends up drwxrws–T: the group s (setgid) makes new files belong to ic2 and the T (sticky) stops Laura from deleting Sergio’s file; Pablo cannot even list it. chmod 3770 submissions: setgid + sticky drwxrws––T 3770 sergio ic2 submissions/ s = setgid (2) new files inherit the ic2 group (lowercase: the group also has x) T = sticky (1) each user deletes only their own files (capital: others have no x) ls -l submissions (laura) -rw-r–r– laura ic2 laura.txt -rw-r–r– sergio ic2 sergio.txt laura$ rm submissions/sergio.txt   laura$ rm submissions/laura.txt   pablo$ ls submissions   rm on someone else’s file: Operation not permitted
Look at the two files: different owners, but the same ic2 group thanks to the s.
  • chgrp ic2 before chmod: setgid makes new things inherit the folder’s group, so the folder has to belong to ic2. Otherwise everything would inherit the sergio group.
  • The lowercase s in the group (rws) means setgid with x. That’s why laura.txt comes out with group ic2, even though Laura’s primary group is laura.
  • The capital T in others (--T) means sticky without the others’ x (others have 0). That’s why Laura gets Operation not permitted when deleting sergio.txt even though she has w on the folder, while she deletes her own laura.txt without any trouble.
  • Pablo is “others” and has ---: he can’t even list it.

The obvious alternative, chmod 770 submissions, meets requirement 1 but not 2 (Laura’s files would belong to the laura group) or 3 (Laura could delete sergio.txt).

Try it in your terminal

Instead of Python Tutor, relive fragment 2 in your terminal, on a small scale. Type the commands after each $ in your test folder:

$ mkdir box
$ touch box/note.txt
$ chmod 644 box
$ ls -l box
ls: cannot access 'box/note.txt': Permission denied
total 0
-????????? ? ? ? ?            ? note.txt
$ chmod 755 box
$ ls -l box
total 0
-rw-r--r-- 1 sergio sergio 0 Oct 25 16:49 note.txt

What to look at:

  1. After chmod 644 box, ls -l box shows the name note.txt (thanks to r), but with question marks in every column (no x).
  2. The cannot access warning comes before the listing: ls tries to look up the file and can’t get through the folder.
  3. After chmod 755 box everything is back: permissions, owner, group, size and date.
  4. Try one more step yourself: chmod 711 box and ls box. What do you think happens now? And cat box/note.txt?

Cheat sheet: Linux permissions

The essentials in 30 seconds

  • ls -l → type + three rwx triplets: owner, group, others, always in that order.
  • Octal: r = 4, w = 2, x = 1; one digit per triplet (754 = rwxr-xr--).
  • Symbolic: for whom (u g o a) + operation (+ - =) + permissions (r w x X).
  • On a folder: r = list, w = create and delete, x = get in.
  • The umask removes: 666 and 777 minus the mask (022 → 644 and 755).
  • Only root can change the owner (chown); the group (chgrp), only to one of your groups.
  • Fourth digit: setuid 4, setgid 2, sticky 1.

Reading and changing permissions

I want to…CommandResult
see permissions, owner and groupls -l file-rw-r--r-- 1 sergio ic2 …
see a folder’s own line, not its contentsls -ld folderdrwxr-x--- …
see octal and letters togetherstat -c '%a %A %n' file640 -rw-r----- file
make a script executablechmod u+x script.shrwxr--r--
group file, read onlychmod 640 filerw-r-----
private filechmod 600 filerw-------
group folder (get in and list)chmod 750 folderrwxr-x---
folder where the group createschmod 770 folderrwxrwx---
remove everything from others in a treechmod -R o-rwx folderothers = --- everywhere
let everyone read a tree without breaking itchmod -R u=rwX,go=rX folderfolders 755, files 644

Owner, group, umask and special bits

I want to…CommandResult
see my groupsidgroups=1001(sergio),1010(ic2)
hand a tree to my groupchgrp -R ic2 foldergroup ic2 everywhere
change the owner (root)sudo chown laura fileowner laura
see the umaskumask / umask -S0022 / u=rwx,g=rx,o=rx
new things at 640 and 750umask 027files 640, folders 750
new things privateumask 077files 600, folders 700
folder that passes on its groupchmod 2770 folderdrwxrws---
folder where everyone deletes only their ownchmod 1777 folderdrwxrwxrwt
group submissionschmod 3770 folderdrwxrws--T

Exercise templates

# Level 1: octal for exact values, symbolic for changes
chmod 640 report.txt
chmod u+x,g+x,o-r build.sh         # 644 → 750
chmod 750 data
# Level 2: umask = what gets switched off
umask 027                          # files 640, folders 750
# Level 3: shared submissions folder
chgrp ic2 submissions
chmod 3770 submissions             # setgid + sticky

With these commands the levels give 640/750/750, 640/750 and drwxrws--T.

Symptom and likely cause

SymptomLikely cause
bash: ./script.sh: Permission deniedthe script lacks the owner’s x: chmod u+x
cd: folder: Permission deniedthe folder lacks the x for your class
-????????? in ls -lthe folder has r but no x
cannot open directorythe folder lacks the r for your class
you can’t create or delete insidethe folder lacks w (and x)
chown: … Operation not permittedonly root changes the owner
rm: … Operation not permitted in a shared foldersticky: it isn’t your file
new files come out weirdcheck the umask (umask, umask -S)
as the owner you can’t, even though the group canLinux only looks at the owner triplet

Before you hand it in, ask yourself

  1. Have I written the triplets in order: owner, group and others?
  2. Do all the folders along the way have the x for whoever needs to reach the file?
  3. Have I used -R with a number where folders and files were mixed?
  4. Have I tested it with a regular user, and not as root?
Keep goingAll Linux articles

Did this article help you? Here is how you can support SergioLearns →

Sigue aprendiendo

Leave a Reply

Your email address will not be published. Required fields are marked *