This is not exactly a question about how to run a hash bang script.
In this situation, a hash bang script exists which doesn't (necessarily) have the
u+s permission. Rather, the interpreter has
u+s, and the script designates that interpreter:
On Mac OS, in this situation, the designated interpreter itself isn't granted the setuid implied by its own permission bits, as it would be if it were directly executed. Its real and effective user ID is just that of the user who ran the hash bang script.
Is there a workaround for this not involving the interpreter re-executing itself?
Kazs-Mac-Pro:txr kaz$ uname -a Darwin Kazs-Mac-Pro.local 11.0.0 Darwin Kernel Version 11.0.0: Fri Apr 8 20:29:42 PDT 2011; root:xnu-1699.22.36~1/RELEASE_X86_64 x86_64 Kazs-Mac-Pro:txr kaz$ cat setuid.tl #!./txr --reexec (put-line `gids: @(getegid) @(getgid)`) (put-line `uids: @(geteuid) @(getuid)`) (put-line `groups: @(getgroups)`) (seteuid 0) ;; throws if unable Kazs-Mac-Pro:txr kaz$ ls -l txr setuid.tl -rwsr-xr-x 1 root wheel 163 5 May 15:18 setuid.tl -rwsr-xr-x 1 root wheel 1334500 5 May 15:17 txr Kazs-Mac-Pro:txr kaz$ ./setuid.tl gids: 20 20 uids: 0 501 groups: 20 402 401 12 33 61 79 80 81 98 100 204
--reexec does is call
execvp on the program's path name, and the remaining arguments after
--reexec. Poof, setuid privs are back. This is ugly, though.
If we do not have
--rexec, this is the behavior:
Kazs-Mac-Pro:txr kaz$ ./setuid.tl gids: 20 20 uids: 501 501 groups: 20 402 401 12 33 61 79 80 81 98 100 204 ./txr: unhandled exception of type system-error: ./txr: seteuid failed: 1/"Operation not permitted" ./txr: during evaluation at ./setuid.tl:4 of form (seteuid 0)
u+s on the script is irrelevant from the system perspective; the interpreter uses that, and the ownership of the script, to decide whether to run the script setuid, or whether to permanently drop privileges and then run it. Of course, we wouldn't want to do this sort of thing with an interpreter that isn't aware of setuid operation and blindly confers its elevated privilege onto any piece of code that it is asked to execute.)