22

If the file is a plain text file created by root with:

echo 'foo' > ./file.txt

Your ls -l is:

-rw-r--r-- root root ./file.txt

But as a regular user, I can change this with vim saving with :w! or with a sed command and when this happened the user and group that owns this file is changed to:

-rw-r--r-- user user ./file.txt

After I noticed that when removed others read permission with chmod o-r ./file.txt I can't do the changes anymore, but when restored with chmod o+r ./file.txt I am able to again.

What is happening here? Why does the "others" read permission enable me to change a file owned by root and also changes the user and group ownership?

Why is this happening?

PS: I'm use Debian SID.

3
  • 7
    Please, add to your question the result of ls -ld ., I guess your directory is o+w, i.e. it allows any user to replace (delete+create) file.txt with their own version of the file.
    – xhienne
    Nov 16, 2023 at 11:12
  • @xhienne, thanks for your help, that was exactly the "problem", my regular user had permission to write to the parent directory.
    – rhuanpk
    Nov 16, 2023 at 13:46
  • 3
    Does this answer your question? How does vim steal root owned files?
    – muru
    Nov 17, 2023 at 8:40

2 Answers 2

46

This is happening because of two things:

  • vim (at least in this case) and sed, when doing in place editing, actually delete the original file and then create a new one with the same name.

  • the ability to delete a file depends on the permissions of the directory containing the file, not on the permissions of the file itself.

So, what is happening here is that you have write permission on the directory, which means you can change the directory's contents, including deleting and creating files. So when you run your sed -i or save with :w!, you are deleting the original and then creating a new file. This is also why the ownership changes: this is actually a different file.

You can demonstrate this by checking the file's inode before and after editing:

$ ls -ld foo/
drwxr-xr-x 2 terdon terdon 266240 Nov 16 13:43 foo/
$ cd foo
$ sudo sh -c 'echo foo > file'
$ ls -l 
total 4
-rw-r--r-- 1 root root 4 Nov 16 13:43 file

After those commands, I have file, owned by root, in the directory foo/ to which my regular user has write permission. Now, let's use ls -i to check the inode, and then make a changed with sed and check again:

$ ls -li file 
26610890 -rw-r--r-- 1 root root 4 Nov 16 13:43 file
$ sed -i 's/foo/bar/' file
$ ls -li file 
26610859 -rw-r--r-- 1 terdon terdon 4 Nov 16 15:40 file

You can also see vim doing the same thing by running

strace vim file 2> strace.out

Then editing the file and saving with :w!. In your strace.out, you will see:

    unlink("file")                           = 0
    open("file", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 4
    write(4, "bar\n", 11)            = 11

So, the file was first deleted (unlink("file")), then a new file of the same name was created (open("file", O_WRONLY|O_CREAT|O_TRUNC, 0644)) and the modifications I had made were written to it (write(4, "bar\n", 11)).

As you can see above, the inode changed: this is a new file with the same name. So you did not actually change a file you didn't have write access to, you changed a directory to which you did have write access by deleting a file in that directory and then creating a new file in the directory with the same name as the old one.

I have answered a similar question here: https://askubuntu.com/a/815849/85695.

7
  • 3
    And then there's the sticky bit getting set on the directory permissions. Just to make it even more complex for someone not familiar with POSIX-style file and directory permissions... :-) Nov 16, 2023 at 11:56
  • 3
    vim doesn't necessarily replace the original file (there are several settings that have an influence on that). But :w! does in any case when it doesn't have write access to the file. Nov 16, 2023 at 11:58
  • @andrew-henle I actually have knowledge about permissions, but I just saw that it's not as much as I thought, in fact we learn more every day.
    – rhuanpk
    Nov 16, 2023 at 13:54
  • 3
    I'd add that the "recreate and delete" behaviour is common unix doctrine. It is derived from the convention that if you modify a file the original one might be saved as a backup (ofter with ~ suffix) and it is that file which should reflect the original ownership and permissions, not the changed one. Nov 17, 2023 at 7:51
  • 1
    sed -i does it slightly differently: It first saves the edited content to a temporary file, then rename(2) the temp file over the original. In case of insufficient permissions, sed will produce different error messages than vim.
    – iBug
    Nov 17, 2023 at 8:13
17

vim cannot modify the file, but if it has write access to the directory that file is linked to and either you own that directory or the t bit in its permissions is not set, then it can delete it and replace it with a new copy owned by you.

To prevent that, root can either

  • set the immutable (chattr +i) or append-only (chattr +a) flag on the file (then even root won't be able to delete it)
  • make sure only root has write access to the parent directory¹ (owned by root and w bit for the user only; chown root:, chmod u=rwx,go=rx)
  • have the directory owned by root, possibly writeable by others but have the t (restricted deletion²) bit (chmod o+t) in the permissions (so users can only delete/rename the files they own).

¹ Beware that for a file called /a/b/file if user has write access to /a, then then can also rename /a/b to /a/b.old and recreate a /a/b and /a/b/file of their own within it.

² you might have heard the sticky-bit term for that bit, but that's when applied to regular executable files (and only on very old systems) where that instructs (used to instruct) the system to keep the text of the executable in memory. When applied to a directory that bit has a different unrelated meaning.

1
  • Your tip is very valuable and I will definitely use it, thank you!
    – rhuanpk
    Nov 16, 2023 at 13:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .