Why I don't trust seteuid() and friends
Unix has a number of methods that a suitably privileged process can
use to temporarily assume another UID, do something with those limited
privileges, and then return back to its old, fully privileged state.
The grandfather of these is probably setreuid(), which appeared
way back in 4.2 BSD.
Normally, there are any number of ways to examine and interfere with
processes that are running under your UID; you can send them signals,
you can stop them, you can use ptrace() or the equivalent to inspect
them, run them as slow as you want, and even inject your own code, and
on some operating systems you can use /proc to gain access to files
that they have open. (This is not an exhaustive list.)
Allowing you to do any of these to a process that is merely temporarily
running with your UID and that actually had elevated privileges opens
up various sorts of security holes. If you can directly inject code
it is an instant 'game over', but even lesser access is dangerous; for
example, such a process may have open file descriptors to files that
contain sensitive information (which it has left open because it was
counting on them staying inaccessible to you).
In theory, Unix kernels prevent you from doing any of these things to
such processes. In practice, people keep adding ways to do things to
your processes (and sometimes they add new ways to do things with less
privileges), and they do not always realize the full implications or,
even if they do, they do not completely protect their mechanism.
The result, at least in my impression, has been a slow stream of ways to
make such temporarily reduced privileges 'leak', to exploit them to gain
extra access or information or the like. As a result I do not trust any
of them to be completely secure all of the time. Which leads me to my
view that if you want complete
security on Unix, you must irrevocably give up all privileges.
On some systems, even many systems, your code will be safe today if you
properly use the right mechanism to temporarily assume another UID (note
all of those qualifiers). But I cannot trust it to stay safe tomorrow
and on another system, because I feel that the whole edifice is simply
too fragile. Irrevocably giving up privileges is harsh, but it is not
fragile, and it is honest; when you write such code, you write it with
the full knowledge that the user can completely hijack your unprivileged
side, and the rest of your code has to be able to deal with that.