Vim can break file permissions?

8

1

I was using Vim the other day as usual, when I noticed something strange. Here's what I did:

~$ touch testfile
~$ ls -l | grep testfile
-rw-r--r-- 1 username groupname 0 Jul 23 10:00 testfile
~$ vim testfile

Then I made a change, and saved and quit with :wq. Pretty normal. Then, however:

~$ sudo chown root:root testfile
~$ sudo chmod 644 testfile
~$ sudo -k
~$ ls -l | grep testfile
-rw-r--r-- root root 0 Jul 23 10:02 testfile
~$ vim testfile

So root should have r/w access and everyone else should have only read. Edit the file, try to save - you can't. Awesome, working as intended. However, if you save with :w!, vim somehow changes the file ownership back to username:usergroup and the file is saved. Even if you do this:

~$ sudo chmod 444 testfile
~$ sudo -k
~$ ls -l | grep testfile
-r--r--r-- 1 root root 0 Jul 23 10:06 testfile
~$ vim testfile

You can still overwrite with :w!! What is happening? How can vim break the laws of file ownership and permission like this? I looked at the help page in vim by saying :help :w and found this:

:w[rite]! [++opt]    Like ":write", but forcefully write when 'readonly' is set or there is another reason why writing was refused.
                     Note: This may change the permission and ownership of the file and break (symbolic) links. Add the 'W' flage to 'cpoptions' to avoid this.

I've been unable to write to a file in vim previously when I shouldn't, so I guess the real heart of my question is, how can I make a file unedit-able by vim and why isn't it based on file system permissions, like I'd expect, and what mechanism is vim using to edit the file that other editors (gedit, nano) can't use?

EDIT: The computer I tried this on is using Linux kernel 3.15.5-2-ARCH. Vim's version number is 7.4.373-1, and it's the one installed by pacman - I didn't compile it from scratch with any special options.

zrneely

Posted 2014-07-23T14:25:01.880

Reputation: 183

I don't seem to be able to reproduce the problem, unless taking some tricks as described here

– Davyzhu – 2014-07-23T14:51:04.613

I just tried it again using the commands in the question, and it happened in the same way. I'll edit the question to add details about my computer though since it seems like this might be platform dependent. – zrneely – 2014-07-23T14:54:10.510

My first hunch is that you're allowed to change ownership of files in a directory you have write access to. But it seems that's not the case. CAP_CHOWN is required to call chown(2). By the way, I can reproduce on Debian, with vim 7.4.

– Bob – 2014-07-23T15:18:51.407

Answers

10

I can see that your current path is ~, your user's home directory. You should have write permissions to that directory.

Think of it another way - if you have read and write permissions to the directory, what's stopping you from copying the file, deleting the old one and renaming the new one with different permissions?

This is exactly what vim does!


If you run vim under strace, for example:

open("testfile", O_WRONLY|O_CREAT|O_TRUNC, 0644) = -1 EACCES (Permission denied)
lstat("testfile", {st_mode=S_IFREG|0644, st_size=10, ...}) = 0
getuid()                                = 1000
unlink("testfile")                      = 0
open("testfile", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 3
write(3, "ffjidfjds\n", 10)             = 10
fsync(3)                                = 0
close(3)                                = 0
chmod("testfile", 0644)                 = 0

Based on this log, I can guess at the following process:

Some earlier permission checks (and chown attempts, etc.) are omitted for brevity.

  1. open Attempt to open the file for writing (fail: permission denied)
  2. lstat Check the owner of the file
  3. getuuid Check the current user ID, to see if they match the file owner
  4. unlink Delete the file (this is allowed because write permission on the directory)
  5. open Create a new file with the same name
  6. write The file contents (read earlier, I typed in some gibberish)
  7. fsync Flush the file to disk (not really important)
  8. close
  9. chmod Change the new file's permissions to look like the old one - it just happens to have a new owner now.

Bob

Posted 2014-07-23T14:25:01.880

Reputation: 51 526

Ok, thanks. I'm glad I got this figured out. So if I don't have write permissions on the directory, I won't be able to use :w!, which makes sense. – zrneely – 2014-07-23T15:30:19.343

Also, the strace information is really handy - now I have another tool for my own investigations in the future. – zrneely – 2014-07-23T15:35:32.313

1@zrneely A tip for strace: use the -o option to write output to a file; otherwise it clashes with vim's output. As for write permissions, I don't see it checking directory permissions with stat but it does attempt to create a file (named 4913, seems random) in the current directory and then delete it. – Bob – 2014-07-23T15:38:25.837

Seems like 4913 is actually just the first name it tries, and its purpose is to check if it has enough permissions to do so. See: https://bugzilla.redhat.com/show_bug.cgi?id=427711#c6 and https://groups.google.com/forum/#%21topic/vim_dev/sppdpElxY44

– Bob – 2014-07-23T15:42:54.713