Bug #500
openset-uid script with -p in magic number gets Exec format error
0%
Description
[Originally filed as http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6934836]
The following script, when run as a set-uid script, fails to execute,
reporting an "Exec format error" instead:
$ cat ok.ksh
#!/bin/ksh -p
print "okay"
$
This is odd because ksh -p is documented as doing nothing more than suppressing the processing of the user's $HOME/.profile and using
/etc/suid_profile instead of the ENV variable. Nothing in available ksh93 documentation suggests that -p is incompatible with set-uid scripts.
Work Around
Remove the options from the #! line and use a "set" line instead to set the same options. For instance, the following line:
#!/usr/bin/ksh -p
can be replaced by these lines:
#!/usr/bin/ksh
set -p
Does not seem to have anything to do with the "-p" option specifically. The script fails in exactly the same way if we use any options, "-x", "-v", etc.
The difference between the way a suid script is executed and a regular one is that in case of a suid script, the script to be executed is passed as a /dev/fd parameter to close the "replace script between exec and open by shell" hole (usr/src/uts/common/exec/shbin/shbin.c). This, with ksh93, seems to have a problem only if there are options specified on the command line.
The program below demonstrates this:
$ cat testexec.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int
main()
{
int fd = -1;
char devfd32;
char *script = "/tmp/ok.ksh";
fd = open(script, O_RDONLY);
sprintf(devfd, "/dev/fd/%d", fd);
execl("/usr/bin/sparcv9/ksh93", "ksh", "-v", devfd, NULL);
//execl("/usr/bin/sparcv9/ksh93", "ksh", "-v", script, NULL);
//execl("/usr/bin/bash", "bash", "-v", devfd, NULL);
//execl("/usr/bin/sparcv9/ksh93", "ksh", devfd, NULL);
perror("exec failed");
}
$ ./testexec
/usr/bin/ksh: /usr/bin/ksh: cannot execute [Exec format error]
This fails irrespective of whether the script is suid or not. And the other commented execl() lines in the source (using the script directly instead of the /dev/fd path, bash with command line options and the devfd path, or ksh93 without command line options) all work perfectly.
A few interesting twists:
$ cp testexec kshexec
$ ./kshexec
okay
(Renaming the script to something starting with 'ksh' makes it start working.)
$ SHELL=/bin/ksh ./testexec
ksh: ksh: cannot execute [Exec format error]
$ SHELL=/bin/bash ./testexec
/usr/bin/ksh: /usr/bin/ksh: cannot execute binary file
(Though we are invoking ksh93 directly, it does an exec of itself when we use /dev/fd/XX scripts where it ends up using the SHELL environment variable.)
The culprit seems to be the code below:
<lib/libshell/common/sh/init.c>
1216 shp->st.dolv=argv+(argc-1)-shp->st.dolc;
1217 shp->st.dolv0 = argv0;
Here, we are overwriting one of the arguments of argv (because shp->st.dolv indexes into the argv vector).
In this particular case, argv which originally looked like this:
ksh, -v, /dev/fd/3
ends up looking like this:
ksh, ksh, /dev/fd/3
We then pass the mangled argv to execv():
<lib/libshell/common/sh/main.c>
298 /* exec to change $0 for ps */
299 execv(pathshell(),av);
As a consequence, ksh tries to load the ksh binary as a shell script and fails with an "Exec format" error.
Files
Updated by Roland Mainz over 11 years ago
- File patch.diff.txt patch.diff.txt added