Hi,

the loop:

1. When ksh starts a binary, it sets its environment variable "_"
to "*number*/path/to/binary". Where "number" is the pid of the ksh process.

2. The binary forks and the child executes a suid root shell script
which begins with #!/bin/sh. On Solaris, this is Korn shell.

3. The ksh process interpreting the suid shell script leaves the "_"
variable as not set (nv_getval(L_ARGNOD) returns NULL) because
the "number" from step 1 is not the pid of its parent process.

4. Because "_" is not set and the script is suid root, the following condition
is true in src/cmd/ksh93/sh/main.c:

296 if(((type = sh_type(cp = av[0])) & SH_TYPE_SH) && (!(name = nv_getval(L_ARGNOD)) || !((type = sh_type(cp = name)) & SH_TYPE_SH)))
297            {

and this code gets executed:

298            av[0] = (type & SH_TYPE_LOGIN) ? cp : path_basename(cp);
299            /*  exec to change $0 for ps */
300            execv(pathshell(),av);
301            /* exec fails */
302            shp->st.dolv[0] = av[0];
303            fixargs(shp->st.dolv,1);
304            }

5. When the SHELL environment variable contains "/bin/sh"
then pathshell() returns "/bin/sh". This becomes an infinite
loop of /bin/sh /dev/fd/3 executing /bin/sh /dev/fd/3.

/dev/fd/3 is the suid root script passed in via file descriptor 3.

The first /bin/sh in the loop is the #!/bin/sh from the suid script.
The second and subsequent /bin/sh in the loop is from
the SHELL environment variable.


This is the fix which avoids the infinite loop:
<fix>
--- /dev/null   Thu Oct 31 04:52:33 2013
+++ new/components/ksh93/patches/17432413.patch Thu Oct 31 04:52:32 2013
@@ -0,0 +1,23 @@
--- a/src/cmd/ksh93/sh/init.c
+++ b/src/cmd/ksh93/sh/init.c
@@ -720,7 +720,7 @@ static char* get_lastarg(Namval_t* np, Namfun_t *fp)
       char    *cp;
       int     pid;
if(sh_isstate(SH_INIT) && (cp=shp->lastarg) && *cp=='*' && (pid=strtol(cp+1,&cp,10)) && *cp=='*')
-              nv_putval(np,(pid==shp->gd->ppid?cp+1:0),0);
+              nv_putval(np,cp+1,0);
       return(shp->lastarg);
 }

--- a/src/cmd/ksh93/sh/main.c
+++ b/src/cmd/ksh93/sh/main.c
@@ -298,7 +298,7 @@ int sh_main(int ac, char *av[], Shinit_f userinit)
                                        */
                                       if (shp->st.repl_index > 0)
av[shp->st.repl_index] = shp->st.repl_arg;
- if(((type = sh_type(cp = av[0])) & SH_TYPE_SH) && (!(name = nv_getval(L_ARGNOD)) || !((type = sh_type(cp = name)) & SH_TYPE_SH))) + if(((type = sh_type(cp = av[0])) & SH_TYPE_SH) && (name = nv_getval(L_ARGNOD)) && (!((type = sh_type(cp = name)) & SH_TYPE_SH)))
                                       {
av[0] = (type & SH_TYPE_LOGIN) ? cp : path_basename(cp); /* exec to change $0 for ps */

</fix>

The get_lastarg() change disables the check whether the "number"
refers to the process id of the parent process.

The sh_main() change prevents infinite loop when the "_" variable
is not passed in from the environment.


This is the source code which sets all the necessary conditions
and triggers the infinite loop:
<source>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#define ERROR \
do{ \
    fprintf(stderr, "[%s, %d] error\n", __FILE__, __LINE__); \
    exit(EXIT_FAILURE); \
}while(0)

int main(int argc, char *argv[])
{
    char devfd[]="/dev/fd/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    char *arg[5];
    int fd;

    if(argc!=2)
        ERROR;

    fd=open(argv[1], O_RDONLY);
    if(fd<0)
        ERROR;

    sprintf(devfd, "/dev/fd/%d", fd);

    arg[0]="sh";
    arg[1]=devfd;
    arg[2]="AAA";
    arg[3]="BBB";
    arg[4]=NULL;

    if(argc>1)
        unsetenv("_");
    else
        setenv("_", "*1234*/garbage", 1);

    setenv("SHELL", "/bin/sh", 1);

    execvp("/bin/sh", arg);

    ERROR;
}
</source>


Is it ok that calling pathshell() on line 300 can actually
lead to a Korn script being executed by Bash for instance?
(when SHELL is set to /bin/bash)


Tomas Klacko
_______________________________________________
ast-developers mailing list
ast-developers@lists.research.att.com
http://lists.research.att.com/mailman/listinfo/ast-developers

Reply via email to