Am I the only one that thinks that the problem is in the way that Linux
defines the semantics of /proc/nnn/fd/n ?
I only think of three sensible ways of doing it.
One could follow exactly what is in the man page, and /proc/nnn/fd/n are
symbolic links to actual files.
Then, if the file is deleted or moved, the link points to nothing. And if
the file is replaced, it points to the new file.
Of course, the drawback is that /proc/nnn/fd/n is not reliably pointing to
the opened file. But that's normal, for a symbolic link.
The second option would have to be /proc/nnn/fd/n a special file rather than
a symbolic link, that behaves exactly like the file descriptor. This special
file would be accessible with exactly the same rights as the ones used to
open the file. For example, if one does
$ exec 3>/tmp/toto; echo tata>&3
then of course we would be able to do
$ cat /tmp/toto
but we would get "Permission denied" when trying
$ cat /proc/self/fd/3
One side effect would be that /proc/nnn/fd/n would never be setuid.
$ echo tutu>/proc/self/fd/3
would append at the end of /tmp/toto, because it would be the same as
$ echo tutu>&3
$ echo tutu>/tmp/toto
The third option, which is the closest to the current semantics, is to have
/proc/xxx/fd/x to be a symbolic link to the file currently in use.
Therefore, like it is the case in Linux, if the file is moved, the symbolic
link is changed (I did not check if there is a race condition there).
But, if the file is deleted, then the symbolic link needs to be a link to an
actual file. The best is probably to use the same trick as for NFS: to
generate a file with a random unique name in the root of the filesystem.
However, it is quite clear to me that the current behaviour is inconsistent
and is the reason of this security flaw. We see
$ ls -l /proc/self/fd/3
pretend that it is a symbolic link to a file that does not exist, and
$ ls -lL /proc/self/fd/3
show a setuid file.