Olaf Kirch:
> Hi all,
>
> when you're dealing with files in /tmp that are supposed to be re-opened
> (rather than opened once and then discarded) there's an established
> way to do it which goes like this:
>
> if (lstat(fname, &stb1) >= 0 && S_ISREG(stb1.st_mode)) {
> fd = open(fname, O_RDWR);
> if (fd < 0 || fstat(fd, &stb2) < 0
> || ino_or_dev_mismatch(&stb1, &stb2))
> raise_big_stink()
> } else {
> /* do the O_EXCL thing */
> }
>
> Accepted wisdom has it that this protects you from symlink attacks.
Olaf explains that this test compares inode information not files
- if the process is setuid, the open() can, at least in theory, be
delayed until the inode found with lstat() has been re-used for
something interesting.
> All of this doesn't make it a practical attack yet, but it surely
> demonstrates that the supposedly secure code shown above is far from
> secure.
>
> Comments? Suggestions?
Three comments. First of all, this demonstrates how problematic it
can be to do privileged work in a process that runs under control
by a user.
For daemon processes that don't run under user control, the above
test can be improved a bit by comparing more attributes than just
device/inode numbers. I'll update a comment to that effect in the
Postfix safe_open() routine, now that I understand my code better.
Thanks for pointing out an interesting flaw in the common assumptions
made about race conditions, namely, that the race is being run at
high speed.
Wietse