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.
Table of Contents
How to use this article
- Read the statement and write the commands on paper or in a file before trying them.
- Try them in a test folder (
mkdir ~/permissions-exercises && cd ~/permissions-exercises), never in your home folder or as root. - Compare with the expected output. If it doesn’t match, read the hint before the solution.
- 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:
- The owner (
sergio) and the group can get in, list and create; others, nothing. - Everything created inside must belong to the
ic2group, whoever creates it. - 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:
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.txtin octal: we want exact permissions, and640reads directly (6 = 4 + 2 =rw-, 4 =r--, 0 =---).build.shin symbolic mode, starting from644. This is the trace of theu+x,g+x,o-rcommand, applied from left to right:
| Part | Before | After | Maths |
|---|---|---|---|
u+x | 644 rw-r--r-- | 744 rwxr--r-- | 6 + 1 = 7 |
g+x | 744 | 754 rwxr-xr-- | 4 + 1 = 5 |
o-r | 754 | 750 rwxr-x--- | 4 − 4 = 0 |
dataat750and not740: withoutxthe group would see the names but couldn’t get in (fragment 2). And not770, becausewwould 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:
| Owner | Group | Others | |
|---|---|---|---|
| File requested (666) | rw- | rw- | rw- |
| What we want (640) | rw- | r-- | --- |
| To switch off | nothing → 0 | w → 2 | everything → 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:
| Digit | Value | Meaning |
|---|---|---|
3 = 2 + 1 | setgid + sticky | inherit the group and each user deletes only their own |
7 | rwx | owner: everything |
7 | rwx | group: get in, list and create |
0 | --- | others: nothing |
The drawing puts the two special bits together with what they cause:
chgrp ic2beforechmod: setgid makes new things inherit the folder’s group, so the folder has to belong toic2. Otherwise everything would inherit thesergiogroup.- The lowercase
sin the group (rws) means setgid withx. That’s whylaura.txtcomes out with groupic2, even though Laura’s primary group islaura. - The capital
Tin others (--T) means sticky without the others’x(others have0). That’s why Laura getsOperation not permittedwhen deletingsergio.txteven though she haswon the folder, while she deletes her ownlaura.txtwithout 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:
- After
chmod 644 box,ls -l boxshows the namenote.txt(thanks tor), but with question marks in every column (nox). - The
cannot accesswarning comes before the listing:lstries to look up the file and can’t get through the folder. - After
chmod 755 boxeverything is back: permissions, owner, group, size and date. - Try one more step yourself:
chmod 711 boxandls box. What do you think happens now? Andcat box/note.txt?
Cheat sheet: Linux permissions
The essentials in 30 seconds
ls -l→ type + threerwxtriplets: 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… | Command | Result |
|---|---|---|
| see permissions, owner and group | ls -l file | -rw-r--r-- 1 sergio ic2 … |
| see a folder’s own line, not its contents | ls -ld folder | drwxr-x--- … |
| see octal and letters together | stat -c '%a %A %n' file | 640 -rw-r----- file |
| make a script executable | chmod u+x script.sh | rwxr--r-- |
| group file, read only | chmod 640 file | rw-r----- |
| private file | chmod 600 file | rw------- |
| group folder (get in and list) | chmod 750 folder | rwxr-x--- |
| folder where the group creates | chmod 770 folder | rwxrwx--- |
| remove everything from others in a tree | chmod -R o-rwx folder | others = --- everywhere |
| let everyone read a tree without breaking it | chmod -R u=rwX,go=rX folder | folders 755, files 644 |
Owner, group, umask and special bits
| I want to… | Command | Result |
|---|---|---|
| see my groups | id | groups=1001(sergio),1010(ic2) |
| hand a tree to my group | chgrp -R ic2 folder | group ic2 everywhere |
| change the owner (root) | sudo chown laura file | owner laura |
| see the umask | umask / umask -S | 0022 / u=rwx,g=rx,o=rx |
| new things at 640 and 750 | umask 027 | files 640, folders 750 |
| new things private | umask 077 | files 600, folders 700 |
| folder that passes on its group | chmod 2770 folder | drwxrws--- |
| folder where everyone deletes only their own | chmod 1777 folder | drwxrwxrwt |
| group submissions | chmod 3770 folder | drwxrws--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
| Symptom | Likely cause |
|---|---|
bash: ./script.sh: Permission denied | the script lacks the owner’s x: chmod u+x |
cd: folder: Permission denied | the folder lacks the x for your class |
-????????? in ls -l | the folder has r but no x |
cannot open directory | the folder lacks the r for your class |
| you can’t create or delete inside | the folder lacks w (and x) |
chown: … Operation not permitted | only root changes the owner |
rm: … Operation not permitted in a shared folder | sticky: it isn’t your file |
| new files come out weird | check the umask (umask, umask -S) |
| as the owner you can’t, even though the group can | Linux only looks at the owner triplet |
Before you hand it in, ask yourself
- Have I written the triplets in order: owner, group and others?
- Do all the folders along the way have the
xfor whoever needs to reach the file? - Have I used
-Rwith a number where folders and files were mixed? - Have I tested it with a regular user, and not as root?
Did this article help you? Here is how you can support SergioLearns →




What is an operating system — theory with your laptop on a study afternoon, a write() call and a CPU that never rests (and the three programs that weren’t running at the same time)