views:

402

answers:

4

Why is it possible to touch a write-protected file?

Shouldn't the following give an error?

$ touch test.txt
$ chmod a-w test.txt
$ ls -l test.txt
-r--r--r-- 1 name group 0 Jun 13 09:14 test.txt
$ touch test.txt && echo OK
OK
$ ls -l test.txt
-r--r--r-- 1 name group 0 Jun 13 09:15 test.txt

Does touch change permissions, touch the file, and change permissions back? Why would it do that?

Given this behavior, if I really want to protect a file so that I (my user) will never (unintentionally) change, remove or change its timestamp in the future -- how can I do it?

(Sorry, not strictly programming-related, but slightly, and probably of interest to many programmers.)

+4  A: 

From the touch (coreutils) documentation:

If changing both the access and modification times to the current time, `touch' can change the timestamps for files that the user running it does not own but has write permission for. Otherwise, the user must own the files.

jrockway
That only seems to cover ownership - the question was about write access so I believe @objlass has it right - timestamps are held in the directory entry, not the file, so write access to the directory is enough to change them.
paxdiablo
That could be a little clearer. Is it saying that if you can `touch` files with either w-perms *or* ownership?
Michael Haren
+7  A: 

The execution permissions of the directory that the file contains dictates the ability to delete or modify the inode information for the entry in the directory that is associated with the file.

As the comment below indicates I have glossed over the technical reason but instead offered a reasoning why the behavior might not be as expected. Since you can execute in the directory there are a number of things you can do to tinker with the file and I am going to leave it at that.

If you want to stop anyone but root from modifying a file the best method is to use the chattr +i filename on the file. Even root will not be able to perform any actions on it without running chattr -i on it. This applies to Linux so YMMV.

ojblass
Could the user touch readonly files that are owned by someone else if said user has execute permissions on the directory?
Michael Haren
You can delete a file that you cannot read in a directory where you have execute permission. There can be a lot of experimentation and variations done but the fact remains permissions of files are not the definitive end all be all indication of the actions you are authorized to perform.
ojblass
Execute permission on the directory is required in order to specify a file name in the directory, but that alone does not permit "touch". For "touch", you must be the owner of the file (as here), or have write permission, or be root.
mark4o
+4  A: 

Here's the relevant output from : strace "touch test.txt"

open("test.txt", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0666) = -1 EACCES (Permission denied)
futimesat(AT_FDCWD, "test.txt", NULL)   = 0

It indeed gets a "Permission denied error" on the open(2) system call regarding EACCES. See relevant section in utimes(2) man page.

However, it does succeed in updating the timestamp using the futimesat(2) system call.

As others have indicated, it looks like the directory permissions hold the rights to update access/moficiation timestamps.

You can, however change the attribute of a file to immutable using:

chattr +i test.txt

Note: Only root can do this, and it's a very harsh way to disable access to files. But in extreme cases, it can be useful. In addition, this is an ext2/3/4 feature, not available on other filesystems as far as I know.

Tom Feiner
You beat me to it Tom, "not programming related" my hat :) OP might like to check the EACCES paragraph in the man page for utimes(2) or futimesat(2), not to mention the souce for touch(1).
Martin Carpenter
Thanks Martin, I added the utimes(2) link to my answer.
Tom Feiner
+3  A: 

You can update the modification time if you own the file, regardless of write permission. (It is not related to any permission on the directory.)

From POSIX.1-2008:

Only a process with the effective user ID equal to the user ID of the file, or with write access to the file, or with appropriate privileges may use futimens() or utimensat() with a null pointer as the times argument or with both tv_nsec fields set to the special value UTIME_NOW. Only a process with the effective user ID equal to the user ID of the file or with appropriate privileges may use futimens() or utimensat() with a non-null times argument that does not have both tv_nsec fields set to UTIME_NOW and does not have both tv_nsec fields set to UTIME_OMIT. If both tv_nsec fields are set to UTIME_OMIT, no ownership or permissions check shall be performed for the file, but other error conditions may still be detected (including [EACCES] errors related to the path prefix).

mark4o