9

As far as I know, when I am creating a new file or directory in a directory that can be written by multiple users (and thus an adversary can have made a symlink there), the only way to protect myself from symlink race is creating a file with enough random name.

Well, some app might have checked if such file already exists, but I am not aware of any mechanism that is both atomic and able to detect symlinks.

So, when there are many non-random (or even reused) filenames in /tmp from various apps, it means all these apps are vulnerable to symlink race, doesn't it? (Well, it can't be simply decided if the vulnerability can be easily abused, but I don't care about practical exploitability for now.)

I hope I must be somewhere wrong.

Shelvacu
  • 2,333
  • 4
  • 16
  • 29
v6ak
  • 609
  • 5
  • 12
  • Have you investigated `mktemp`? – MattBianco Mar 05 '15 at 10:08
  • 1
    @MattBianco Sure, it is just an implementation of "creating a file with enough random name". Unfortunately, it seems that there are many apps that don't use it. – v6ak Mar 05 '15 at 10:10
  • 1
    There's you answer then. It is as common as there are bad implementations of tempfile creation. One way of atomically creating a file is by (hard)linking to it with (`ln` without `-s`). Only one process will succeed in creating the link. – MattBianco Mar 05 '15 at 10:14
  • OK, such creation prevents it, but I think this is unlikely, since it must be preceded by creating a file with a random name, so it is harder that just creating a file with a random name. – v6ak Mar 05 '15 at 10:52
  • 7
    `open(..., O_EXCL|O_CREAT)` you could also use `fd=open` and `fstat(fd` to check if file is a link without having the race condition. – domen Mar 05 '15 at 11:29
  • @domen Can you elaborate the "open" then "fstat" idea? I do not think it can prevent symlink race. "fstat" returns the information from the inode of the opened file. You do not know whether it is the file provided by an attacker or not. I agree with "open(..., O_EXCL|O_CREAT)" though. – Infinite Jan 20 '17 at 18:05
  • 1
    @Infinite good catch. I wasn't clear enough. `open` with `O_NOFOLLOW`, then `fstat` to tell you if it's a symlink. – domen Jan 20 '17 at 20:16

1 Answers1

5

So this should answer the question of "is symlink common?"

A search on the MITRE database shows there are 4 CVEs for a Linux Symlink Race condition vulnerability. For comparison, there are 2749 Linux CVEs known to MITRE.

Linux at the kernel level has protections against this. Kees Cook created a patch for Linux to prevent this problem:

The solution is to permit symlinks to only be followed when outside a sticky world-writable directory, or when the uid of the symlink and follower match, or when the directory owner matches the symlink's owner.

Ohnana
  • 4,737
  • 2
  • 23
  • 39
  • I don't think Kees Cook's Linux patch was ever accepted. – Macil Nov 29 '17 at 21:54
  • 3
    @AgentME: Looks to me like it was: https://github.com/torvalds/linux/commit/800179c9b8a1e796e441674776d11cd4c05d61d7 seems to be included in tags starting at v3.6-rc1. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=800179c9b8a1e796e441674776d11cd4c05d61d7 is the more canonical URL. – MvG Feb 20 '18 at 18:13
  • FWIW, Kees did not come up with the patch. This was long-standing behavior in grsecurity. – forest Apr 18 '18 at 07:24