A related problem is the inherent race condition:
If you do
ln -s /bin/setuidscript .
./setuidscript
./setuidscript is opened twice: once when the kernel
reads it and finds #! as magic number and execs the
interpreter, a second time when the interpreter opens
./setuidscript. If you meanwhile run something that
swoops in in the background and replaces ./setuidscript
with malicious instructions for the interpreter, you
win.
This was always described to me as the canonical reason why setuid
interpreted scripts were a security hole, irrespective of any specifics
in the shell or other interpreter.
However, there's a workaround: use fdescfs. fdescfs allows the kernel to
open the script, and then pass the fdescfs path for the (already open)
descriptor to the interpreter as the command to run.
According to
https://www.in-ulm.de/~mascheck/various/shebang/#setuid, this
is supported by many systems, including Solaris, several BSDs, and OSX
(with a sysctl).
-Jason