diff --git a/sys/amd64/linux/syscalls.master b/sys/amd64/linux/syscalls.master --- a/sys/amd64/linux/syscalls.master +++ b/sys/amd64/linux/syscalls.master @@ -439,8 +439,8 @@ 59 AUE_EXECVE STD { int linux_execve( char *path, - char **argp, - char **envp + l_uintptr_t *argp, + l_uintptr_t *envp ); } 60 AUE_EXIT STD { diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c --- a/sys/amd64/linux32/linux32_machdep.c +++ b/sys/amd64/linux32/linux32_machdep.c @@ -114,20 +114,6 @@ return (copyout(&lru, uaddr, sizeof(struct l_rusage))); } -int -linux_execve(struct thread *td, struct linux_execve_args *args) -{ - struct image_args eargs; - int error; - - error = freebsd32_exec_copyin_args(&eargs, args->path, UIO_USERSPACE, - args->argp, args->envp); - if (error == 0) - error = linux_common_execve(td, &eargs); - AUDIT_SYSCALL_EXIT(error == EJUSTRETURN ? 0 : error, td); - return (error); -} - CTASSERT(sizeof(struct l_iovec32) == 8); int diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master --- a/sys/amd64/linux32/syscalls.master +++ b/sys/amd64/linux32/syscalls.master @@ -102,8 +102,8 @@ 11 AUE_EXECVE STD { int linux_execve( char *path, - uint32_t *argp, - uint32_t *envp + l_uintptr_t *argp, + l_uintptr_t *envp ); } 12 AUE_CHDIR STD { diff --git a/sys/arm64/linux/syscalls.master b/sys/arm64/linux/syscalls.master --- a/sys/arm64/linux/syscalls.master +++ b/sys/arm64/linux/syscalls.master @@ -1357,8 +1357,8 @@ 221 AUE_EXECVE STD { int linux_execve( char *path, - char **argp, - char **envp + l_uintptr_t *argp, + l_uintptr_t *envp ); } 222 AUE_MMAP STD { diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -2555,7 +2555,89 @@ } } -#ifndef COMPAT_LINUX32 +/* + * Custom version of exec_copyin_args(), to copy out argument and environment + * strings from the old process address space into the temporary string buffer. + * Based on freebsd32_exec_copyin_args. + */ +static int +linux_exec_copyin_args(struct image_args *args, const char *fname, + enum uio_seg segflg, l_uintptr_t *argv, l_uintptr_t *envv) +{ + char *argp, *envp; + l_uintptr_t *ptr, arg; + int error; + + bzero(args, sizeof(*args)); + if (argv == NULL) + return (EFAULT); + + /* + * Allocate demand-paged memory for the file name, argument, and + * environment strings. + */ + error = exec_alloc_args(args); + if (error != 0) + return (error); + + /* + * Copy the file name. + */ + error = exec_args_add_fname(args, fname, segflg); + if (error != 0) + goto err_exit; + + /* + * extract arguments first + */ + ptr = argv; + for (;;) { + error = copyin(ptr++, &arg, sizeof(arg)); + if (error) + goto err_exit; + if (arg == 0) + break; + argp = PTRIN(arg); + error = exec_args_add_arg(args, argp, UIO_USERSPACE); + if (error != 0) + goto err_exit; + } + + /* + * This comment is from Linux do_execveat_common: + * When argv is empty, add an empty string ("") as argv[0] to + * ensure confused userspace programs that start processing + * from argv[1] won't end up walking envp. + */ + if (args->argc == 0 && + (error = exec_args_add_arg(args, "", UIO_SYSSPACE) != 0)) + goto err_exit; + + /* + * extract environment strings + */ + if (envv) { + ptr = envv; + for (;;) { + error = copyin(ptr++, &arg, sizeof(arg)); + if (error) + goto err_exit; + if (arg == 0) + break; + envp = PTRIN(arg); + error = exec_args_add_env(args, envp, UIO_USERSPACE); + if (error != 0) + goto err_exit; + } + } + + return (0); + +err_exit: + exec_free_args(args); + return (error); +} + int linux_execve(struct thread *td, struct linux_execve_args *args) { @@ -2564,11 +2646,10 @@ LINUX_CTR(execve); - error = exec_copyin_args(&eargs, args->path, UIO_USERSPACE, + error = linux_exec_copyin_args(&eargs, args->path, UIO_USERSPACE, args->argp, args->envp); if (error == 0) error = linux_common_execve(td, &eargs); AUDIT_SYSCALL_EXIT(error == EJUSTRETURN ? 0 : error, td); return (error); } -#endif diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master --- a/sys/i386/linux/syscalls.master +++ b/sys/i386/linux/syscalls.master @@ -102,8 +102,8 @@ 11 AUE_EXECVE STD { int linux_execve( char *path, - char **argp, - char **envp + l_uintptr_t *argp, + l_uintptr_t *envp ); } 12 AUE_CHDIR STD {