OnCallReady

Lesson 4.7 · Filesystem, Permissions, Disk · 18 min read

r and x mean something else on a directory

In plain words

A directory is like a phone book. Being allowed to read the phone book (r) means you can see the list of names. Being allowed to use the phone book (x) means you can look up a name you already know and get its number, even if you are not allowed to flip through the pages. Being allowed to write in it (w) means you can add or cross out names, even of people you do not know.

So on a directory, r is list, x is traverse, w is create and delete. 711 means "you may reach what you have been told about, but not browse". The question marks from ls -l mean r without x. And to reach /srv/vault/report.txt, you need x on every directory on the way; namei -l walks the path and shows which one blocks you.

Why "the file is 644" is not the whole answer

A file can be perfectly readable and still unreachable. The same three letters mean something different on a directory, and most "I set the file to 644 and it still says Permission denied" tickets are really a directory problem.

What you need to know already: 4.5 (permission bits, octal, which triple applies), 4.3 (sudo -u).

On a file

r  read the contents
w  modify the contents
x  execute it

On a directory

A directory is a file whose content is a table of name -> inode number (an inode is the record that really is the file - 4.13 explains it; here, think "the file itself"). The bits apply to that table:

x  TRAVERSE: use this directory as part of a path. Required to reach, stat or
   open anything inside it - even something you already know the name of.
r  LIST: read the table, i.e. see the filenames.
w  change the table: create, rename and DELETE entries (needs x as well).

Every combination, with what you actually see

Set up once:

$ mkdir -p /tmp/d/sub && echo x > /tmp/d/sub/file

rw- (600) - read, no x. You can read the table but not use it:

$ chmod 600 /tmp/d
$ ls /tmp/d
sub
$ cat /tmp/d/sub/file
cat: /tmp/d/sub/file: Permission denied

r-- (400) - list only. ls gets the names from the table, then cannot look up any of them, so the long listing is question marks:

$ chmod 400 /tmp/d
$ ls -l /tmp/d
ls: cannot access '/tmp/d/sub': Permission denied
total 0
d????????? ? ? ? ?            ? sub

That ????????? line is diagnostic: it always means "r without x on the directory". Almost never what anyone intended.

--x (100) - traverse only. You cannot list, but a name you know works:

$ chmod 100 /tmp/d
$ ls /tmp/d
ls: cannot open directory '/tmp/d': Permission denied
$ cat /tmp/d/sub/file
x

This is the useful one. Mode 711 on a directory means "you may reach what you have been told about, but you may not browse". Home directories on shared machines are sometimes 711 so a known path inside works without everyone being able to read the list of what is there.

-wx (300) - write and traverse, no list. You can create and delete names blind. This is how old-school "drop" directories worked.

Why w on a directory is the dangerous one

Deleting a file is a change to the directory (its name table), not to the file. So write permission on a directory lets you delete files inside it that you do not own and cannot even read:

$ mkdir /tmp/drop; chgrp ops /tmp/drop; chmod 775 /tmp/drop
$ echo 'Q4 plan' > /tmp/drop/plan.txt; chgrp ops /tmp/drop/plan.txt; chmod 440 /tmp/drop/plan.txt
$ ls -ld /tmp/drop; ls -l /tmp/drop/plan.txt
drwxrwxr-x 2 learner ops 4096 Sep 22 20:00 /tmp/drop
-r--r----- 1 learner ops 8 Sep 22 20:00 /tmp/drop/plan.txt
$ sudo -u appuser rm -f /tmp/drop/plan.txt     # appuser: in ops, cannot read it
$ ls /tmp/drop/plan.txt
ls: cannot access '/tmp/drop/plan.txt': No such file or directory

That is what the sticky bit fixes (4.9), and why /tmp has it.

The rule for a path

To open /a/b/c/file you need x on /, /a, /a/b and /a/b/c, and then the right permission on file. One missing x anywhere up the chain and nothing below is reachable.

namei -l PATH walks the path and shows the mode and owner at every level (-l = long, like ls -l). It is the fastest way to find the level that is wrong:

$ namei -l /srv/vault/report.txt
f: /srv/vault/report.txt
drwxr-xr-x root root /
drwxr-xr-x root root srv
drwx------ root root vault
report.txt - Permission denied

Read it top to bottom as the user in question: / - other has x, fine. srv - fine. vault - drwx------, other has nothing: stop, that is the level. namei cannot even look at report.txt, and says so.

Testing as someone else

Never reason about another user's access and stop there - try it:

sudo -u appuser cat /srv/vault/report.txt
sudo -u www-data ls /var/www/reports
sudo -u appuser test -r /path && echo readable

test -r FILE (also -w, -x) exits 0 if the user running it could read (write, execute) the file - it asks the kernel the exact question, so you do not have to work it out yourself.

What you can now do

Why it helps

"I gave the file 644 and the service still cannot read it" is almost always a directory with a missing x higher up the path, and namei -l finds it in one command. This comes up constantly with application configs under home directories, web roots, volume mounts and shared storage.

The w-on-directory rule matters for security: anyone with write access to a directory can delete or replace files in it, even files they cannot read, which is how a writable /opt/app directory lets a compromised user swap a binary that root later runs. Knowing the sticky bit fixes this for shared directories, and that 711 home directories allow access without browsing, are practical design choices you will make.

Commands in this lesson

mkdir chmod ls cat echo rm namei

FAQ

What do the question marks in ls -l mean?

You have read permission on the directory (so ls could list the names) but not execute (so it could not stat the entries to get their mode, owner and size). Output like d????????? ? ? ? ? ? sub together with "cannot access ... Permission denied" is the signature of r without x on the directory. It is almost never intended; add x or remove r.

Can I delete a file I cannot read?

Yes, if you have write and execute permission on the directory containing it. Deleting removes an entry from the directory, which is a change to the directory, not to the file. The file's own permissions are irrelevant (rm asks for confirmation on write-protected files, but proceeds). The sticky bit on the directory is what restricts deletion to the file's owner.

Why is 711 used on home directories?

It lets other users traverse the home directory to reach specific paths they know, like ~alice/public_html for a web server, without letting them list what else is there. Owner has full access; group and others have only x. On Ubuntu, recent releases create home directories as 750, so other users cannot even traverse; that is stricter and usually better on shared machines.

What does namei -l do?

It splits a path into its components and shows the type, mode, owner and group of every one, from / down to the target, following symlinks. You read it as the user in question and find the first level that does not grant x (or r for the final file). It is the quickest way to debug path permission problems, often faster than reasoning about each ls -ld separately.

Does a symlink's permission matter?

No. Symlinks always show lrwxrwxrwx and those bits are not used on Linux. What matters is the target's permissions and x on every directory in the target's path. A symlink pointing into a directory you cannot traverse cannot be followed, however open the link looks. Also, protected_symlinks in /tmp-style directories restricts following other users' links.

In an interview Junior

What do read, write and execute mean on a directory?

A directory is a table of name -> inode, and the bits apply to that table:

Consequences: --x (as in 711) lets people reach a file by name without browsing the directory. w on a directory lets you delete files inside that you do not own and cannot read - which is why /tmp needs the sticky bit. And for a path, you need x on every directory from / down, then the right bit on the file.

To debug: namei -l /srv/vault/report.txt shows the mode at each level, and sudo -u appuser cat ... proves it as that user.

Also asked: A web server cannot read a 644 file under a user's home directory. How do you find out why? · Why is write permission on a directory more dangerous than write on the file? · How do you test whether another user can read a file, without guessing?

Practise this lesson in the terminal Free, in your browser - a real Ubuntu terminal to try it in, with missions that check your work.