Your analysis of the situation is incorrect, rbatte.
While you are correct that mount options can forbid suid binary executables (and even non-suid executables), linux does not support suid
interpreted script executables, regardless of mount options.
Regards,
Alister
---------- Post updated at 02:06 PM ---------- Previous update was at 12:04 PM ----------
In case anyone is interested, a more detailed explanation.
Relevant functions from the 3.9.7 stable kernel:
fs/exec.c :: do_execve_common()
fs/exec.c :: prepare_binprm()
fs/exec.c :: search_binary_handler()
fs/binfmt_script.c :: load_script()
Linux can support many executable formats. Each format has a dedicated handler registered with the kernel. When loading an executable, the execve syscall must first identify the format of the executable. This is accomplished in search_binary_handler by walking the list of registered handlers until one of them succeeds. If none succeed, the system call fails.
This procedure can occur more than once. A typical, successful shell script execve requires two passes. The first pass ends with the success of load_script, the handler that recognizes the #! shebang header. This handler parses the interpreter's pathname from the shebang line and uses it to begin the second pass. Usually, the interpreter is a native binary (e.g. sh, awk, perl, etc), in which case this second handler search concludes with load_elf_binary.
The kernel calls prepare_binprm before each pass.
prepare_binprm resets the effective uid and gid to match that of the current process (execve's caller), before checking the inode of the executable it intends to load. If the inode's mode has a SUID/SGID bit set, then the euid/egid for the to-be-loaded executable is set to match the inode uid/gid (incidentally, rbatte, this is also where the NOSUID mount option check is located).
The first prepare_binprm call is in do_execve_common and involves the SUID shell script executable. The second call is in load_script and involves the interpreter pathname.
Between the two calls to prepare_binprm, the relevant data structure actually has the shell script owner's credentials, as if the kernel intends to allow the change in ownership. However, the second prepare_binprm invocation (just as the first) resets the euid/egid values to those of the current process. The shell script's inode's SUID/SGID change is clobbered and this time prepare_binprm consults the interpreter's inode, not the shell script's.
Regards,
Alister