0

I am trying to understand the corner case behaviors of rm command. In a folder owned and grouped by root, I have a file owned by user alice. However, user alice does not have any permissions on the file and containing folder is owner and grouped by root. (here I use the term grouped, meaning that it belongs to that group)

There are three scenarios when trying to remove the file based on other's permission bits of the folder.

Scenario 1: others have read and write permission. In this case, rm command removes the file with a prompt:

alice@cherry:.../folder_root$ sudo ls -alFh
total 0
drwx----wx 1 root  root  4.0K Dec 10 15:14 ./
drwxr-xr-x 1 alice alice 4.0K Dec 10 14:39 ../
---------- 1 alice alice    0 Dec 10 15:14 foo
alice@cherry:.../folder_root$ rm foo
rm: remove write-protected regular empty file 'foo'? yes
alice@cherry:.../folder_root$ sudo ls -alFh
total 0
drwx----wx 1 root  root  4.0K Dec 10 15:21 ./
drwxr-xr-x 1 alice alice 4.0K Dec 10 14:39 ../
alice@cherry:.../folder_root$

In the case that the other's permission bits is only execute, then we have the following behavior:

alice@cherry:.../folder_root$ rm foo
rm: remove write-protected regular empty file 'foo'? yes
rm: cannot remove 'foo': Permission denied
alice@cherry:.../folder_root$ sudo ls -alFh
total 0
drwx-----x 1 root  root  4.0K Dec 10 15:14 ./
drwxr-xr-x 1 alice alice 4.0K Dec 10 14:39 ../
---------- 1 alice alice    0 Dec 10 15:14 foo

Now in the case that other's permission bits of the folder is only read, then here is the behavior:

alice@cherry:.../folder_root$ rm foo
rm: cannot remove 'foo': Permission denied
alice@cherry:.../folder_root$ sudo ls -la
total 0
drwx----w- 1 root  root  4096 Dec 10 15:14 .
drwxr-xr-x 1 alice alice 4096 Dec 10 14:39 ..
---------- 1 alice alice    0 Dec 10 15:14 foo

I guess I don't understand why the read and execute permission bits are required to remove the file. Why is this the behavior?

milaniez
  • 103

1 Answers1

1

My testbed is Linux, namely Debian 12, and in this answer I link to Debian manuals. Still I believe the mechanics is identical in all Unix/Linux systems.

I don't understand why the read and execute permission bits are required to remove the file. Why is this the behavior?

Your examples show that you need write and "execute" permissions on the directory. The first example shows that you actually don't need read permission.

You need write permission bit on the directory because removing a file means unlinking it, i.e. removing its directory entry. This act modifies the directory, not the file.

You need "execute" permission bit on the directory because it's really a search permission bit:

execute/search by […] ("search" applies for directories, and means that entries within the directory can be accessed)

(source: man 2 chmod)

Relevant parts of man 7 path_resolution [emphasis mine]:

If the pathname does not start with the / character, the starting lookup directory of the resolution process is the current working directory of the process […]

[…]

Set the current lookup directory to the starting lookup directory. Now, for each nonfinal component of the pathname, where a component is a substring delimited by / characters, this component is looked up in the current lookup directory.

If the process does not have search permission on the current lookup directory, an EACCES error is returned ("Permission denied").

[…]

If the component is found and is a directory, we set the current lookup directory to that directory, and go to the next component.

[…]

The lookup of the final component of the pathname goes just like that of all other components, as described in the previous step, with two differences: (i) the final component need not be a directory […]

(The second difference is irrelevant for our issue.)

When rm is going to remove foo, the OS needs to resolve foo. The string foo is the pathname, it does not start with /, so the starting lookup directory of the resolution process is the current working directory of rm. This directory is then called current lookup directory. The lack of search permission on the current lookup directory results in "Permission denied".

Normally you would get "Permission denied" when trying to cd to a directory without search permission. I guess you changed the ownership and/or the mode of the directory in question after cd-ing to it in your unelevated shell. If the directory appeared as a component in the pathname supplied to rm, it would be clear that the search permission on it would matter. For a relative path the search permission on the current working directory is the first one the OS checks anyway, even if the directory does not appear in the pathname. The fact you are already in the directory cannot help.

In some cases being already in the right directory can help. If you were in a directory (let's call it lower) with write and search permission bits, but without search permission on the parent directory (let's call it upper) and if there was foo in the directory, then you could do rm foo or rm ./foo, but you couldn't do rm ../lower/foo or rm "$PWD"/foo. This is a case where the fact you are already in a directory you cannot cd to from "outside" does allow you to manipulate files by using (some) relative paths. You are below the non-searchable directory. The lack of search permission on the parent directory manifests itself (with "Permission denied") only for pathnames that contain a component that resolves to the parent directory.

In your example you were exactly in the non-searchable directory. For relative paths the search permission on the current working directory always matters.