Index: sys/kern/imgact_aout.c =================================================================== --- sys/kern/imgact_aout.c +++ sys/kern/imgact_aout.c @@ -328,7 +328,7 @@ (virtual_offset + a_out->a_text); /* Fill in image_params */ - imgp->interpreted = 0; + imgp->interpreted = NULL; imgp->entry_addr = a_out->a_entry; imgp->proc->p_sysent = &aout_sysvec; Index: sys/kern/imgact_binmisc.c =================================================================== --- sys/kern/imgact_binmisc.c +++ sys/kern/imgact_binmisc.c @@ -599,14 +599,6 @@ return (-1); } - /* No interpreter nesting allowed. */ - if (imgp->interpreted) { - mtx_unlock(&interp_list_mtx); - return (ENOEXEC); - } - - imgp->interpreted = 1; - if (imgp->args->fname != NULL) { fname = imgp->args->fname; sname = NULL; Index: sys/kern/imgact_elf.c =================================================================== --- sys/kern/imgact_elf.c +++ sys/kern/imgact_elf.c @@ -977,7 +977,7 @@ elf_auxargs->entry = entry; imgp->auxargs = elf_auxargs; - imgp->interpreted = 0; + imgp->interpreted = NULL; imgp->reloc_base = addr; imgp->proc->p_osrel = osrel; Index: sys/kern/imgact_gzip.c =================================================================== --- sys/kern/imgact_gzip.c +++ sys/kern/imgact_gzip.c @@ -285,7 +285,7 @@ (gz->virtual_offset + gz->a_out.a_text); /* Fill in image_params */ - gz->ip->interpreted = 0; + gz->ip->interpreted = NULL; gz->ip->entry_addr = gz->a_out.a_entry; gz->ip->proc->p_sysent = &aout_sysvec; Index: sys/kern/imgact_shell.c =================================================================== --- sys/kern/imgact_shell.c +++ sys/kern/imgact_shell.c @@ -112,15 +112,6 @@ return (-1); /* - * Don't allow a shell script to be the shell for a shell - * script. :-) - */ - if (imgp->interpreted) - return (ENOEXEC); - - imgp->interpreted = 1; - - /* * At this point we have the first page of the file mapped. * However, we don't know how far into the page the contents are * valid -- the actual file might be much shorter than the page. Index: sys/kern/kern_exec.c =================================================================== --- sys/kern/kern_exec.c +++ sys/kern/kern_exec.c @@ -360,6 +360,7 @@ struct pmckern_procexec pe; #endif static const char fexecv_proc_title[] = "(fexecv)"; + int num_interpreted = 0; imgp = &image_params; @@ -385,7 +386,7 @@ imgp->entry_addr = 0; imgp->reloc_base = 0; imgp->vmspace_destroyed = 0; - imgp->interpreted = 0; + imgp->interpreted = NULL; imgp->opened = 0; imgp->interpreter_name = NULL; imgp->auxargs = NULL; @@ -497,14 +498,33 @@ /* * Loop through the list of image activators, calling each one. * An activator returns -1 if there is no match, 0 on success, - * and an error otherwise. + * and an error otherwise. Skip over an interpreter, if we have + * already invoked and saved its address into imgp->interpreted. */ - for (i = 0; error == -1 && execsw[i]; ++i) { + for (i = 0; error == -1 && execsw[i] && + num_interpreted < MAXINTERPRETED; ++i) { if (execsw[i]->ex_imgact == NULL || - execsw[i]->ex_imgact == img_first) { + execsw[i]->ex_imgact == img_first || + execsw[i]->ex_imgact == imgp->interpreted) { + /* + * If we have already run this interpreter on this + * argv[0], clear interpreted and continue. + */ + if (imgp->interpreted == execsw[i]->ex_imgact) + imgp->interpreted = NULL; continue; } error = (*execsw[i]->ex_imgact)(imgp); + /* + * If an activator runs to completion and indicates success, + * store the address of the activator that was used on this + * pass, this will be used by all activators that need to + * protect themselves from recursion, e.g. shell, binmisc + */ + if (!error) { + imgp->interpreted = execsw[i]->ex_imgact; + num_interpreted++; + } } if (error) { Index: sys/sys/imgact.h =================================================================== --- sys/sys/imgact.h +++ sys/sys/imgact.h @@ -37,6 +37,8 @@ #include #define MAXSHELLCMDLEN PAGE_SIZE +#define MAXINTERPRETED 10 /* Maximum times argv[0] is allowed + * to be adjusted in do_exec() */ struct image_args { char *buf; /* pointer to string buffer */ @@ -61,7 +63,7 @@ unsigned long entry_addr; /* entry address of target executable */ unsigned long reloc_base; /* load address of image */ char vmspace_destroyed; /* flag - we've blown away original vm space */ - char interpreted; /* flag - this executable is interpreted */ + int (*interpreted)(); /* Address of last imgact function run */ char opened; /* flag - we have opened executable vnode */ char *interpreter_name; /* name of the interpreter */ void *auxargs; /* ELF Auxinfo structure pointer */