diff options
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/imgact_aout.c | 7 | ||||
-rw-r--r-- | sys/kern/imgact_elf.c | 11 | ||||
-rw-r--r-- | sys/kern/imgact_gzip.c | 6 | ||||
-rw-r--r-- | sys/kern/imgact_shell.c | 138 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 208 | ||||
-rw-r--r-- | sys/kern/kern_kse.c | 8 |
6 files changed, 215 insertions, 163 deletions
diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c index 9263384..12086fa 100644 --- a/sys/kern/imgact_aout.c +++ b/sys/kern/imgact_aout.c @@ -90,7 +90,7 @@ aout_fixup(stack_base, imgp) struct image_params *imgp; { - return (suword(--(*stack_base), imgp->argc)); + return (suword(--(*stack_base), imgp->args->argc)); } static int @@ -187,11 +187,6 @@ exec_aout_imgact(imgp) } PROC_UNLOCK(imgp->proc); - /* copy in arguments and/or environment from old process */ - error = exec_extract_strings(imgp); - if (error) - return (error); - /* * Destroy old process VM and create a new one (with a new stack) */ diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index ee723e9..03e7f90 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -528,8 +528,6 @@ __elfN(load_file)(struct proc *p, const char *file, u_long *addr, * Initialize part of the common data */ imgp->proc = p; - imgp->userspace_argv = NULL; - imgp->userspace_envv = NULL; imgp->attr = attr; imgp->firstpage = NULL; imgp->image_header = NULL; @@ -647,7 +645,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) u_long text_addr = 0, data_addr = 0; u_long seg_size, seg_addr; u_long addr, entry = 0, proghdr = 0; - int error, i; + int error = 0, i; const char *interp = NULL; Elf_Brandinfo *brand_info; char *path; @@ -706,9 +704,6 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) if (interp != NULL && brand_info->interp_newpath != NULL) interp = brand_info->interp_newpath; - if ((error = exec_extract_strings(imgp)) != 0) - goto fail; - exec_new_vmspace(imgp, sv); vmspace = imgp->proc->p_vmspace; @@ -879,7 +874,7 @@ __elfN(freebsd_fixup)(register_t **stack_base, struct image_params *imgp) Elf_Addr *pos; base = (Elf_Addr *)*stack_base; - pos = base + (imgp->argc + imgp->envc + 2); + pos = base + (imgp->args->argc + imgp->args->envc + 2); if (args->trace) { AUXARGS_ENTRY(pos, AT_DEBUG, 1); @@ -900,7 +895,7 @@ __elfN(freebsd_fixup)(register_t **stack_base, struct image_params *imgp) imgp->auxargs = NULL; base--; - suword(base, (long)imgp->argc); + suword(base, (long)imgp->args->argc); *stack_base = (register_t *)base; return (0); } diff --git a/sys/kern/imgact_gzip.c b/sys/kern/imgact_gzip.c index 0885976..d44d49d 100644 --- a/sys/kern/imgact_gzip.c +++ b/sys/kern/imgact_gzip.c @@ -225,12 +225,6 @@ do_aout_hdr(struct imgact_gzip * gz) /* Find out how far we should go */ gz->file_end = gz->file_offset + gz->a_out.a_text + gz->a_out.a_data; - /* copy in arguments and/or environment from old process */ - error = exec_extract_strings(gz->ip); - if (error) { - gz->where = __LINE__; - return (error); - } /* * Destroy old process VM and create a new one (with a new stack) */ diff --git a/sys/kern/imgact_shell.c b/sys/kern/imgact_shell.c index b34e0c1..07bcd57 100644 --- a/sys/kern/imgact_shell.c +++ b/sys/kern/imgact_shell.c @@ -42,15 +42,15 @@ __FBSDID("$FreeBSD$"); /* * Shell interpreter image activator. An interpreter name beginning - * at imgp->stringbase is the minimal successful exit requirement. + * at imgp->args->begin_argv is the minimal successful exit requirement. */ int exec_shell_imgact(imgp) struct image_params *imgp; { const char *image_header = imgp->image_header; - const char *ihp, *line_endp; - char *interp; + const char *ihp; + int error, length, offset; /* a shell script? */ if (((const short *) image_header)[0] != SHELLMAGIC) @@ -66,64 +66,110 @@ exec_shell_imgact(imgp) imgp->interpreted = 1; /* - * Copy shell name and arguments from image_header into string - * buffer. + * Figure out the number of bytes that need to be reserved in the + * argument string to copy the contents of the interpreter's command + * line into the argument string. */ + ihp = &image_header[2]; + offset = 0; + while (ihp < &image_header[MAXSHELLCMDLEN]) { + /* Skip any whitespace */ + while ((*ihp == ' ') || (*ihp == '\t')) { + ihp++; + continue; + } + + /* End of line? */ + if ((*ihp == '\n') || (*ihp == '#')) + break; + + /* Found a token */ + while ((*ihp != ' ') && (*ihp != '\t') && (*ihp != '\n') && + (*ihp != '#')) { + offset++; + ihp++; + } + /* Include terminating nulls in the offset */ + offset++; + } + + /* If the script gives a null line as the interpreter, we bail */ + if (offset == 0) + return (ENOEXEC); + + /* Check that we aren't too big */ + if (offset > MAXSHELLCMDLEN) + return (ENAMETOOLONG); /* - * Find end of line; return if the line > MAXSHELLCMDLEN long. + * The full path name of the original script file must be tagged + * onto the end, adjust the offset to deal with it. + * + * The original argv[0] is being replaced, set 'length' to the number + * of bytes being removed. So 'offset' is the number of bytes being + * added and 'length' is the number of bytes being removed. */ - for (ihp = &image_header[2]; *ihp != '\n'; ++ihp) { - if (ihp >= &image_header[MAXSHELLCMDLEN]) - return(ENAMETOOLONG); - } - line_endp = ihp; + offset += strlen(imgp->args->fname) + 1; /* add fname */ + length = (imgp->args->argc == 0) ? 0 : + strlen(imgp->args->begin_argv) + 1; /* bytes to delete */ - /* reset for another pass */ - ihp = &image_header[2]; + if (offset - length > imgp->args->stringspace) + return (E2BIG); - /* Skip over leading spaces - until the interpreter name */ - while ((*ihp == ' ') || (*ihp == '\t')) ihp++; + bcopy(imgp->args->begin_argv + length, imgp->args->begin_argv + offset, + imgp->args->endp - (imgp->args->begin_argv + length)); - /* copy the interpreter name */ - interp = imgp->interpreter_name; - while ((ihp < line_endp) && (*ihp != ' ') && (*ihp != '\t')) - *interp++ = *ihp++; - *interp = '\0'; + offset -= length; /* calculate actual adjustment */ + imgp->args->begin_envv += offset; + imgp->args->endp += offset; + imgp->args->stringspace -= offset; - /* Disallow a null interpreter filename */ - if (*imgp->interpreter_name == '\0') - return(ENOEXEC); + /* + * If there were no arguments then we've added one, otherwise + * decr argc remove old argv[0], incr argc for fname add, net 0 + */ + if (imgp->args->argc == 0) + imgp->args->argc = 1; - /* reset for another pass */ + /* + * Loop through the interpreter name yet again, copying as + * we go. + */ ihp = &image_header[2]; + offset = 0; + while (ihp < &image_header[MAXSHELLCMDLEN]) { + /* Skip whitespace */ + while ((*ihp == ' ' || *ihp == '\t')) { + ihp++; + continue; + } + + /* End of line? */ + if ((*ihp == '\n') || (*ihp == '#')) + break; - /* copy the interpreter name and arguments */ - while (ihp < line_endp) { - /* Skip over leading spaces */ - while ((*ihp == ' ') || (*ihp == '\t')) ihp++; - - if (ihp < line_endp) { - /* - * Copy to end of token. No need to watch stringspace - * because this is at the front of the string buffer - * and the maximum shell command length is tiny. - */ - while ((ihp < line_endp) && (*ihp != ' ') && (*ihp != '\t')) { - *imgp->stringp++ = *ihp++; - imgp->stringspace--; - } - - *imgp->stringp++ = 0; - imgp->stringspace--; - - imgp->argc++; + /* Found a token, copy it */ + while ((*ihp != ' ') && (*ihp != '\t') && + (*ihp != '\n') && (*ihp != '#')) { + imgp->args->begin_argv[offset++] = *ihp++; } + imgp->args->begin_argv[offset++] = '\0'; + imgp->args->argc++; } - imgp->argv0 = imgp->fname; + /* + * Finally, add the filename onto the end for the interpreter to + * use and copy the interpreter's name to imgp->interpreter_name + * for exec to use. + */ + error = copystr(imgp->args->fname, imgp->args->buf + offset, + imgp->args->stringspace, &length); + + if (error == 0) + error = copystr(imgp->args->begin_argv, imgp->interpreter_name, + MAXSHELLCMDLEN, &length); - return(0); + return (error); } /* diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 50fea85..3998726 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -79,8 +79,8 @@ MALLOC_DEFINE(M_PARGS, "proc-args", "Process arguments"); static int sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS); static int sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS); static int sysctl_kern_stackprot(SYSCTL_HANDLER_ARGS); -static int do_execve(struct thread *td, char *fname, char **argv, - char **envv, struct mac *mac_p); +static int do_execve(struct thread *td, struct image_args *args, + struct mac *mac_p); /* XXX This should be vm_size_t. */ SYSCTL_PROC(_kern, KERN_PS_STRINGS, ps_strings, CTLTYPE_ULONG|CTLFLAG_RD, @@ -171,8 +171,18 @@ execve(td, uap) char **envv; } */ *uap; { + int error; + struct image_args args; + + error = exec_copyin_args(&args, uap->fname, UIO_USERSPACE, + uap->argv, uap->envv); + + if (error == 0) + error = kern_execve(td, &args, NULL); + + exec_free_args(&args); - return (kern_execve(td, uap->fname, uap->argv, uap->envv, NULL)); + return (error); } #ifndef _SYS_SYSPROTO_H_ @@ -197,21 +207,28 @@ __mac_execve(td, uap) struct mac *mac_p; } */ *uap; { - #ifdef MAC - return (kern_execve(td, uap->fname, uap->argv, uap->envv, - uap->mac_p)); + int error; + struct image_args args; + + error = exec_copyin_args(&args, uap->fname, UIO_USERSPACE, + uap->argv, uap->envv); + + if (error == 0) + error = kern_execve(td, &args, uap->mac_p); + + exec_free_args(&args); + + return (error); #else return (ENOSYS); #endif } int -kern_execve(td, fname, argv, envv, mac_p) +kern_execve(td, args, mac_p) struct thread *td; - char *fname; - char **argv; - char **envv; + struct image_args *args; struct mac *mac_p; { struct proc *p = td->td_proc; @@ -226,7 +243,7 @@ kern_execve(td, fname, argv, envv, mac_p) PROC_UNLOCK(p); } - error = do_execve(td, fname, argv, envv, mac_p); + error = do_execve(td, args, mac_p); if (p->p_flag & P_HADTHREADS) { PROC_LOCK(p); @@ -235,7 +252,7 @@ kern_execve(td, fname, argv, envv, mac_p) * force other threads to suicide. */ if (error == 0) - thread_single(SINGLE_EXIT); + thread_single(SINGLE_EXIT); else thread_single_end(); PROC_UNLOCK(p); @@ -251,11 +268,9 @@ kern_execve(td, fname, argv, envv, mac_p) * MPSAFE */ static int -do_execve(td, fname, argv, envv, mac_p) +do_execve(td, args, mac_p) struct thread *td; - char *fname; - char **argv; - char **envv; + struct image_args *args; struct mac *mac_p; { struct proc *p = td->td_proc; @@ -300,12 +315,8 @@ do_execve(td, fname, argv, envv, mac_p) * Initialize part of the common data */ imgp->proc = p; - imgp->userspace_argv = argv; - imgp->userspace_envv = envv; imgp->execlabel = NULL; imgp->attr = &attr; - imgp->argc = imgp->envc = 0; - imgp->argv0 = NULL; imgp->entry_addr = 0; imgp->vmspace_destroyed = 0; imgp->interpreted = 0; @@ -316,6 +327,7 @@ do_execve(td, fname, argv, envv, mac_p) imgp->firstpage = NULL; imgp->ps_strings = 0; imgp->auxarg_size = 0; + imgp->args = args; #ifdef MAC error = mac_execve_enter(imgp, mac_p); @@ -325,18 +337,6 @@ do_execve(td, fname, argv, envv, mac_p) } #endif - /* - * Allocate temporary demand zeroed space for argument and - * environment strings - */ - imgp->stringbase = (char *)kmem_alloc_wait(exec_map, ARG_MAX); - if (imgp->stringbase == NULL) { - error = ENOMEM; - mtx_lock(&Giant); - goto exec_fail; - } - imgp->stringp = imgp->stringbase; - imgp->stringspace = ARG_MAX; imgp->image_header = NULL; /* @@ -345,20 +345,16 @@ do_execve(td, fname, argv, envv, mac_p) */ ndp = &nd; NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME, - UIO_USERSPACE, fname, td); + UIO_SYSSPACE, args->fname, td); mtx_lock(&Giant); interpret: error = namei(ndp); - if (error) { - kmem_free_wakeup(exec_map, (vm_offset_t)imgp->stringbase, - ARG_MAX); + if (error) goto exec_fail; - } imgp->vp = ndp->ni_vp; - imgp->fname = fname; /* * Check file permissions (also 'opens' file) @@ -387,7 +383,7 @@ interpret: /* * If the current process has a special image activator it - * wants to try first, call it. For example, emulating shell + * wants to try first, call it. For example, emulating shell * scripts differently. */ error = -1; @@ -460,7 +456,7 @@ interpret: if (p->p_sysent->sv_fixup != NULL) (*p->p_sysent->sv_fixup)(&stack_base, imgp); else - suword(--stack_base, imgp->argc); + suword(--stack_base, imgp->args->argc); /* * For security and other reasons, the file descriptor table cannot @@ -473,7 +469,7 @@ interpret: */ newcred = crget(); euip = uifind(attr.va_uid); - i = imgp->endargs - imgp->stringbase; + i = imgp->args->begin_envv - imgp->args->begin_argv; if (ps_arg_cache_limit >= i + sizeof(struct pargs)) newargs = pargs_alloc(i); @@ -662,7 +658,7 @@ interpret: /* Cache arguments if they fit inside our allowance */ if (ps_arg_cache_limit >= i + sizeof(struct pargs)) { - bcopy(imgp->stringbase, newargs->ar_args, i); + bcopy(imgp->args->begin_argv, newargs->ar_args, i); p->p_args = newargs; newargs = NULL; } @@ -718,10 +714,6 @@ exec_fail_dealloc: vput(imgp->vp); } - if (imgp->stringbase != NULL) - kmem_free_wakeup(exec_map, (vm_offset_t)imgp->stringbase, - ARG_MAX); - if (imgp->object != NULL) vm_object_deallocate(imgp->object); @@ -739,7 +731,7 @@ exec_fail: PROC_LOCK(p); p->p_flag &= ~P_INEXEC; PROC_UNLOCK(p); - + if (imgp->vmspace_destroyed) { /* sorry, no more process anymore. exit gracefully */ #ifdef MAC @@ -925,73 +917,95 @@ exec_new_vmspace(imgp, sv) * address space into the temporary string buffer. */ int -exec_extract_strings(imgp) - struct image_params *imgp; +exec_copyin_args(struct image_args *args, char *fname, + enum uio_seg segflg, char **argv, char **envv) { - char **argv, **envv; - char *argp, *envp; - int error; - size_t length; + char *argp, *envp; + int error; + size_t length; + + error = 0; + bzero(args, sizeof(*args)); + if (argv == NULL) + return (EFAULT); /* - * extract arguments first + * Allocate temporary demand zeroed space for argument and + * environment strings */ + args->buf = (char *) kmem_alloc_wait(exec_map, PATH_MAX + ARG_MAX); + if (args->buf == NULL) + return (ENOMEM); + args->begin_argv = args->buf; + args->endp = args->begin_argv; + args->stringspace = ARG_MAX; + + args->fname = args->buf + ARG_MAX; - argv = imgp->userspace_argv; + /* + * Copy the file name. + */ + error = (segflg == UIO_SYSSPACE) ? + copystr(fname, args->fname, PATH_MAX, &length) : + copyinstr(fname, args->fname, PATH_MAX, &length); + if (error != 0) { + if (error == ENAMETOOLONG) + return (E2BIG); + return (error); + } - if (argv) { - argp = (caddr_t)(intptr_t)fuword(argv); - if (argp == (caddr_t)-1) + /* + * extract arguments first + */ + while ((argp = (caddr_t) (intptr_t) fuword(argv++))) { + if (argp == (caddr_t) -1) return (EFAULT); - if (argp) - argv++; - if (imgp->argv0) - argp = imgp->argv0; - if (argp) { - do { - if (argp == (caddr_t)-1) - return (EFAULT); - if ((error = copyinstr(argp, imgp->stringp, - imgp->stringspace, &length))) { - if (error == ENAMETOOLONG) - return (E2BIG); - return (error); - } - imgp->stringspace -= length; - imgp->stringp += length; - imgp->argc++; - } while ((argp = (caddr_t)(intptr_t)fuword(argv++))); + if ((error = copyinstr(argp, args->endp, + args->stringspace, &length))) { + if (error == ENAMETOOLONG) + return (E2BIG); + return (error); } - } else - return (EFAULT); + args->stringspace -= length; + args->endp += length; + args->argc++; + } - imgp->endargs = imgp->stringp; + args->begin_envv = args->endp; /* * extract environment strings */ - - envv = imgp->userspace_envv; - if (envv) { while ((envp = (caddr_t)(intptr_t)fuword(envv++))) { if (envp == (caddr_t)-1) return (EFAULT); - if ((error = copyinstr(envp, imgp->stringp, - imgp->stringspace, &length))) { + if ((error = copyinstr(envp, args->endp, + args->stringspace, &length))) { if (error == ENAMETOOLONG) return (E2BIG); return (error); } - imgp->stringspace -= length; - imgp->stringp += length; - imgp->envc++; + args->stringspace -= length; + args->endp += length; + args->envc++; } } return (0); } +void +exec_free_args(struct image_args *args) +{ + + if (args->buf) { + kmem_free_wakeup(exec_map, + (vm_offset_t)args->buf, PATH_MAX + ARG_MAX); + args->buf = NULL; + } +} + /* * Copy strings out to the new process address space, constructing * new arg and env vector tables. Return a pointer to the base @@ -1019,7 +1033,7 @@ exec_copyout_strings(imgp) if (p->p_sysent->sv_szsigcode != NULL) szsigcode = *(p->p_sysent->sv_szsigcode); destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE - - roundup((ARG_MAX - imgp->stringspace), sizeof(char *)); + roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); /* * install sigcode @@ -1044,30 +1058,32 @@ exec_copyout_strings(imgp) * the arg and env vector sets,and imgp->auxarg_size is room * for argument of Runtime loader. */ - vectp = (char **)(destp - (imgp->argc + imgp->envc + 2 + - imgp->auxarg_size) * sizeof(char *)); + vectp = (char **)(destp - (imgp->args->argc + + imgp->args->envc + 2 + imgp->auxarg_size) * + sizeof(char *)); - } else + } else { /* * The '+ 2' is for the null pointers at the end of each of * the arg and env vector sets */ - vectp = (char **)(destp - (imgp->argc + imgp->envc + 2) * + vectp = (char **)(destp - (imgp->args->argc + imgp->args->envc + 2) * sizeof(char *)); + } /* * vectp also becomes our initial stack base */ stack_base = (register_t *)vectp; - stringp = imgp->stringbase; - argc = imgp->argc; - envc = imgp->envc; + stringp = imgp->args->begin_argv; + argc = imgp->args->argc; + envc = imgp->args->envc; /* * Copy out strings - arguments and environment. */ - copyout(stringp, destp, ARG_MAX - imgp->stringspace); + copyout(stringp, destp, ARG_MAX - imgp->args->stringspace); /* * Fill in "ps_strings" struct for ps, w, etc. diff --git a/sys/kern/kern_kse.c b/sys/kern/kern_kse.c index d0e03ec..4e648f5 100644 --- a/sys/kern/kern_kse.c +++ b/sys/kern/kern_kse.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/imgact.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/proc.h> @@ -176,6 +177,7 @@ int kse_thr_interrupt(struct thread *td, struct kse_thr_interrupt_args *uap) { struct kse_execve_args args; + struct image_args iargs; struct proc *p; struct thread *td2; struct kse_upcall *ku; @@ -261,7 +263,11 @@ kse_thr_interrupt(struct thread *td, struct kse_thr_interrupt_args *uap) error = copyin((void *)uap->data, &args, sizeof(args)); if (error) return (error); - error = kern_execve(td, args.path, args.argv, args.envp, NULL); + error = exec_copyin_args(&iargs, args.path, UIO_USERSPACE, + args.argv, args.envp); + if (error == 0) + error = kern_execve(td, &iargs, NULL); + exec_free_args(&iargs); if (error == 0) { PROC_LOCK(p); SIGSETOR(td->td_siglist, args.sigpend); |