git: 6039e966ff27 - main - linux(4): Deduplicate linux_copyout_strings().

From: Dmitry Chagin <dchagin_at_FreeBSD.org>
Date: Thu, 02 Feb 2023 14:59:09 UTC
The branch main has been updated by dchagin:

URL: https://cgit.FreeBSD.org/src/commit/?id=6039e966ff276ff6bcb57f2f70e7d8ff376b24fd

commit 6039e966ff276ff6bcb57f2f70e7d8ff376b24fd
Author:     Dmitry Chagin <dchagin@FreeBSD.org>
AuthorDate: 2023-02-02 14:58:07 +0000
Commit:     Dmitry Chagin <dchagin@FreeBSD.org>
CommitDate: 2023-02-02 14:58:07 +0000

    linux(4): Deduplicate linux_copyout_strings().
    
    It is still present in the 32-bit Linuxulator on amd64.
    
    MFC after:              1 week
---
 sys/amd64/linux/linux_sysvec.c | 130 +---------------------------------
 sys/arm64/linux/linux_sysvec.c | 143 +-------------------------------------
 sys/compat/linux/linux_elf.c   | 153 +++++++++++++++++++++++++++++++++++++++++
 sys/compat/linux/linux_elf.h   |   1 +
 sys/i386/linux/linux_sysvec.c  | 122 +-------------------------------
 5 files changed, 158 insertions(+), 391 deletions(-)

diff --git a/sys/amd64/linux/linux_sysvec.c b/sys/amd64/linux/linux_sysvec.c
index 12a673d87c96..b42c90abc07d 100644
--- a/sys/amd64/linux/linux_sysvec.c
+++ b/sys/amd64/linux/linux_sysvec.c
@@ -115,8 +115,6 @@ extern const char *linux_syscallnames[];
 
 SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
 
-static int	linux_copyout_strings(struct image_params *imgp,
-		    uintptr_t *stack_base);
 static bool	linux_trans_osrel(const Elf_Note *note, int32_t *osrel);
 static void	linux_vdso_install(const void *param);
 static void	linux_vdso_deinstall(const void *param);
@@ -268,132 +266,6 @@ linux_copyout_auxargs(struct image_params *imgp, uintptr_t base)
 	return (error);
 }
 
-/*
- * Copy strings out to the new process address space, constructing new arg
- * and env vector tables. Return a pointer to the base so that it can be used
- * as the initial stack pointer.
- */
-static int
-linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
-{
-	int argc, envc, error;
-	char **vectp;
-	char *stringp;
-	uintptr_t destp, ustringp;
-	struct ps_strings *arginfo;
-	char canary[LINUX_AT_RANDOM_LEN];
-	size_t execpath_len;
-	struct proc *p;
-
-	p = imgp->proc;
-	arginfo = (struct ps_strings *)PROC_PS_STRINGS(p);
-	destp = (uintptr_t)arginfo;
-
-	if (imgp->execpath != NULL && imgp->auxargs != NULL) {
-		execpath_len = strlen(imgp->execpath) + 1;
-		destp -= execpath_len;
-		destp = rounddown2(destp, sizeof(void *));
-		imgp->execpathp = (void *)destp;
-		error = copyout(imgp->execpath, imgp->execpathp, execpath_len);
-		if (error != 0)
-			return (error);
-	}
-
-	/* Prepare the canary for SSP. */
-	arc4rand(canary, sizeof(canary), 0);
-	destp -= roundup(sizeof(canary), sizeof(void *));
-	imgp->canary = (void *)destp;
-	error = copyout(canary, imgp->canary, sizeof(canary));
-	if (error != 0)
-		return (error);
-
-	/* Allocate room for the argument and environment strings. */
-	destp -= ARG_MAX - imgp->args->stringspace;
-	destp = rounddown2(destp, sizeof(void *));
-	ustringp = destp;
-
-	if (imgp->auxargs) {
-		/*
-		 * Allocate room on the stack for the ELF auxargs
-		 * array.  It has LINUX_AT_COUNT entries.
-		 */
-		destp -= LINUX_AT_COUNT * sizeof(Elf64_Auxinfo);
-		destp = rounddown2(destp, sizeof(void *));
-	}
-
-	vectp = (char **)destp;
-
-	/*
-	 * Allocate room for the argv[] and env vectors including the
-	 * terminating NULL pointers.
-	 */
-	vectp -= imgp->args->argc + 1 + imgp->args->envc + 1;
-
-	/*
-	 * Starting with 2.24, glibc depends on a 16-byte stack alignment.
-	 * One "long argc" will be prepended later.
-	 */
-	vectp = (char **)((((uintptr_t)vectp + 8) & ~0xF) - 8);
-
-	/* vectp also becomes our initial stack base. */
-	*stack_base = (uintptr_t)vectp;
-
-	stringp = imgp->args->begin_argv;
-	argc = imgp->args->argc;
-	envc = imgp->args->envc;
-
-	/* Copy out strings - arguments and environment. */
-	error = copyout(stringp, (void *)ustringp,
-	    ARG_MAX - imgp->args->stringspace);
-	if (error != 0)
-		return (error);
-
-	/* Fill in "ps_strings" struct for ps, w, etc. */
-	if (suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp) != 0 ||
-	    suword(&arginfo->ps_nargvstr, argc) != 0)
-		return (EFAULT);
-
-	/* Fill in argument portion of vector table. */
-	for (; argc > 0; --argc) {
-		if (suword(vectp++, ustringp) != 0)
-			return (EFAULT);
-		while (*stringp++ != 0)
-			ustringp++;
-		ustringp++;
-	}
-
-	/* A null vector table pointer separates the argp's from the envp's. */
-	if (suword(vectp++, 0) != 0)
-		return (EFAULT);
-
-	if (suword(&arginfo->ps_envstr, (long)(intptr_t)vectp) != 0 ||
-	    suword(&arginfo->ps_nenvstr, envc) != 0)
-		return (EFAULT);
-
-	/* Fill in environment portion of vector table. */
-	for (; envc > 0; --envc) {
-		if (suword(vectp++, ustringp) != 0)
-			return (EFAULT);
-		while (*stringp++ != 0)
-			ustringp++;
-		ustringp++;
-	}
-
-	/* The end of the vector table is a null pointer. */
-	if (suword(vectp, 0) != 0)
-		return (EFAULT);
-
-	if (imgp->auxargs) {
-		vectp++;
-		error = imgp->sysent->sv_copyout_auxargs(imgp,
-		    (uintptr_t)vectp);
-		if (error != 0)
-			return (error);
-	}
-
-	return (0);
-}
-
 /*
  * Reset registers to default values on exec.
  */
@@ -707,7 +579,7 @@ struct sysentvec elf_linux_sysvec = {
 	.sv_psstringssz	= sizeof(struct ps_strings),
 	.sv_stackprot	= VM_PROT_ALL,
 	.sv_copyout_auxargs = linux_copyout_auxargs,
-	.sv_copyout_strings = linux_copyout_strings,
+	.sv_copyout_strings = __linuxN(copyout_strings),
 	.sv_setregs	= linux_exec_setregs,
 	.sv_fixlimit	= NULL,
 	.sv_maxssiz	= NULL,
diff --git a/sys/arm64/linux/linux_sysvec.c b/sys/arm64/linux/linux_sysvec.c
index eafdbcbabff8..169dafe26ed2 100644
--- a/sys/arm64/linux/linux_sysvec.c
+++ b/sys/arm64/linux/linux_sysvec.c
@@ -105,10 +105,6 @@ extern const char *linux_syscallnames[];
 
 SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
 
-static int	linux_copyout_strings(struct image_params *imgp,
-		    uintptr_t *stack_base);
-static int	linux_elf_fixup(uintptr_t *stack_base,
-		    struct image_params *iparams);
 static bool	linux_trans_osrel(const Elf_Note *note, int32_t *osrel);
 static void	linux_vdso_install(const void *param);
 static void	linux_vdso_deinstall(const void *param);
@@ -127,7 +123,6 @@ LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
 /* DTrace probes */
 LIN_SDT_PROBE_DEFINE0(sysvec, linux_exec_setregs, todo);
 LIN_SDT_PROBE_DEFINE0(sysvec, linux_copyout_auxargs, todo);
-LIN_SDT_PROBE_DEFINE0(sysvec, linux_elf_fixup, todo);
 
 LINUX_VDSO_SYM_CHAR(linux_platform);
 LINUX_VDSO_SYM_INTPTR(kern_timekeep_base);
@@ -225,140 +220,6 @@ linux_copyout_auxargs(struct image_params *imgp, uintptr_t base)
 	return (error);
 }
 
-static int
-linux_elf_fixup(uintptr_t *stack_base, struct image_params *imgp)
-{
-
-	LIN_SDT_PROBE0(sysvec, linux_elf_fixup, todo);
-
-	return (0);
-}
-
-/*
- * Copy strings out to the new process address space, constructing new arg
- * and env vector tables. Return a pointer to the base so that it can be used
- * as the initial stack pointer.
- * LINUXTODO: deduplicate against other linuxulator archs
- */
-static int
-linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
-{
-	char **vectp;
-	char *stringp;
-	uintptr_t destp, ustringp;
-	struct ps_strings *arginfo;
-	char canary[LINUX_AT_RANDOM_LEN];
-	size_t execpath_len;
-	struct proc *p;
-	int argc, envc, error;
-
-	p = imgp->proc;
-	arginfo = (struct ps_strings *)PROC_PS_STRINGS(p);
-	destp = (uintptr_t)arginfo;
-
-	if (imgp->execpath != NULL && imgp->auxargs != NULL) {
-		execpath_len = strlen(imgp->execpath) + 1;
-		destp -= execpath_len;
-		destp = rounddown2(destp, sizeof(void *));
-		imgp->execpathp = (void *)destp;
-		error = copyout(imgp->execpath, imgp->execpathp, execpath_len);
-		if (error != 0)
-			return (error);
-	}
-
-	/* Prepare the canary for SSP. */
-	arc4rand(canary, sizeof(canary), 0);
-	destp -= roundup(sizeof(canary), sizeof(void *));
-	imgp->canary = (void *)destp;
-	error = copyout(canary, imgp->canary, sizeof(canary));
-	if (error != 0)
-		return (error);
-
-	/* Allocate room for the argument and environment strings. */
-	destp -= ARG_MAX - imgp->args->stringspace;
-	destp = rounddown2(destp, sizeof(void *));
-	ustringp = destp;
-
-	if (imgp->auxargs) {
-		/*
-		 * Allocate room on the stack for the ELF auxargs
-		 * array.  It has up to LINUX_AT_COUNT entries.
-		 */
-		destp -= LINUX_AT_COUNT * sizeof(Elf64_Auxinfo);
-		destp = rounddown2(destp, sizeof(void *));
-	}
-
-	vectp = (char **)destp;
-
-	/*
-	 * Allocate room for argc and the argv[] and env vectors including the
-	 * terminating NULL pointers.
-	 */
-	vectp -= 1 + imgp->args->argc + 1 + imgp->args->envc + 1;
-	vectp = (char **)STACKALIGN(vectp);
-
-	/* vectp also becomes our initial stack base. */
-	*stack_base = (uintptr_t)vectp;
-
-	stringp = imgp->args->begin_argv;
-	argc = imgp->args->argc;
-	envc = imgp->args->envc;
-
-	/* Copy out strings - arguments and environment. */
-	error = copyout(stringp, (void *)ustringp,
-	    ARG_MAX - imgp->args->stringspace);
-	if (error != 0)
-		return (error);
-
-	/* Fill in "ps_strings" struct for ps, w, etc. */
-	if (suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp) != 0 ||
-	    suword(&arginfo->ps_nargvstr, argc) != 0)
-		return (EFAULT);
-
-	if (suword(vectp++, argc) != 0)
-		return (EFAULT);
-
-	/* Fill in argument portion of vector table. */
-	for (; argc > 0; --argc) {
-		if (suword(vectp++, ustringp) != 0)
-			return (EFAULT);
-		while (*stringp++ != 0)
-			ustringp++;
-		ustringp++;
-	}
-
-	/* A null vector table pointer separates the argp's from the envp's. */
-	if (suword(vectp++, 0) != 0)
-		return (EFAULT);
-
-	if (suword(&arginfo->ps_envstr, (long)(intptr_t)vectp) != 0 ||
-	    suword(&arginfo->ps_nenvstr, envc) != 0)
-		return (EFAULT);
-
-	/* Fill in environment portion of vector table. */
-	for (; envc > 0; --envc) {
-		if (suword(vectp++, ustringp) != 0)
-			return (EFAULT);
-		while (*stringp++ != 0)
-			ustringp++;
-		ustringp++;
-	}
-
-	/* The end of the vector table is a null pointer. */
-	if (suword(vectp, 0) != 0)
-		return (EFAULT);
-
-	if (imgp->auxargs) {
-		vectp++;
-		error = imgp->sysent->sv_copyout_auxargs(imgp,
-		    (uintptr_t)vectp);
-		if (error != 0)
-			return (error);
-	}
-
-	return (0);
-}
-
 /*
  * Reset registers to default values on exec.
  */
@@ -554,7 +415,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 struct sysentvec elf_linux_sysvec = {
 	.sv_size	= LINUX_SYS_MAXSYSCALL,
 	.sv_table	= linux_sysent,
-	.sv_fixup	= linux_elf_fixup,
+	.sv_fixup	= __elfN(freebsd_fixup),
 	.sv_sendsig	= linux_rt_sendsig,
 	.sv_sigcode	= &_binary_linux_vdso_so_o_start,
 	.sv_szsigcode	= &linux_szsigcode,
@@ -572,7 +433,7 @@ struct sysentvec elf_linux_sysvec = {
 	.sv_psstringssz	= sizeof(struct ps_strings),
 	.sv_stackprot	= VM_PROT_READ | VM_PROT_WRITE,
 	.sv_copyout_auxargs = linux_copyout_auxargs,
-	.sv_copyout_strings = linux_copyout_strings,
+	.sv_copyout_strings = __linuxN(copyout_strings),
 	.sv_setregs	= linux_exec_setregs,
 	.sv_fixlimit	= NULL,
 	.sv_maxssiz	= NULL,
diff --git a/sys/compat/linux/linux_elf.c b/sys/compat/linux/linux_elf.c
index 1da919f02a81..3e0582e2b8c3 100644
--- a/sys/compat/linux/linux_elf.c
+++ b/sys/compat/linux/linux_elf.c
@@ -41,6 +41,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <sys/exec.h>
 #include <sys/imgact.h>
 #include <sys/imgact_elf.h>
 #include <sys/lock.h>
@@ -50,6 +51,11 @@ __FBSDID("$FreeBSD$");
 #include <sys/procfs.h>
 #include <sys/reg.h>
 #include <sys/sbuf.h>
+#include <sys/sysent.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
 
 #include <machine/elf.h>
 
@@ -61,6 +67,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/../linux/linux.h>
 #endif
 #include <compat/linux/linux_elf.h>
+#include <compat/linux/linux_misc.h>
 
 struct l_elf_siginfo {
 	l_int		si_signo;
@@ -312,3 +319,149 @@ __linuxN(note_nt_auxv)(void *arg, struct sbuf *sb, size_t *sizep)
 		PRELE(p);
 	}
 }
+
+/*
+ * Copy strings out to the new process address space, constructing new arg
+ * and env vector tables. Return a pointer to the base so that it can be used
+ * as the initial stack pointer.
+ */
+int
+__linuxN(copyout_strings)(struct image_params *imgp, uintptr_t *stack_base)
+{
+	char canary[LINUX_AT_RANDOM_LEN];
+	char **vectp;
+	char *stringp;
+	uintptr_t destp, ustringp;
+	struct ps_strings *arginfo;
+	struct proc *p;
+	size_t execpath_len;
+	int argc, envc;
+	int error;
+
+	p = imgp->proc;
+	destp =	PROC_PS_STRINGS(p);
+	arginfo = imgp->ps_strings = (void *)destp;
+
+	/*
+	 * Copy the image path for the rtld.
+	 */
+	if (imgp->execpath != NULL && imgp->auxargs != NULL) {
+		execpath_len = strlen(imgp->execpath) + 1;
+		destp -= execpath_len;
+		destp = rounddown2(destp, sizeof(void *));
+		imgp->execpathp = (void *)destp;
+		error = copyout(imgp->execpath, imgp->execpathp, execpath_len);
+		if (error != 0)
+			return (error);
+	}
+
+	/*
+	 * Prepare the canary for SSP.
+	 */
+	arc4rand(canary, sizeof(canary), 0);
+	destp -= sizeof(canary);
+	imgp->canary = (void *)destp;
+	error = copyout(canary, imgp->canary, sizeof(canary));
+	if (error != 0)
+		return (error);
+	imgp->canarylen = sizeof(canary);
+
+	/*
+	 * Allocate room for the argument and environment strings.
+	 */
+	destp -= ARG_MAX - imgp->args->stringspace;
+	destp = rounddown2(destp, sizeof(void *));
+	ustringp = destp;
+
+	if (imgp->auxargs) {
+		/*
+		 * Allocate room on the stack for the ELF auxargs
+		 * array.  It has up to LINUX_AT_COUNT entries.
+		 */
+		destp -= LINUX_AT_COUNT * sizeof(Elf_Auxinfo);
+		destp = rounddown2(destp, sizeof(void *));
+	}
+
+	vectp = (char **)destp;
+
+	/*
+	 * Allocate room for the argv[] and env vectors including the
+	 * terminating NULL pointers.
+	 */
+	vectp -= imgp->args->argc + 1 + imgp->args->envc + 1;
+
+	/*
+	 * Starting with 2.24, glibc depends on a 16-byte stack alignment.
+	 */
+	vectp = (char **)((((uintptr_t)vectp + 8) & ~0xF) - 8);
+
+	/*
+	 * vectp also becomes our initial stack base
+	 */
+	*stack_base = (uintptr_t)vectp;
+
+	stringp = imgp->args->begin_argv;
+	argc = imgp->args->argc;
+	envc = imgp->args->envc;
+
+	/*
+	 * Copy out strings - arguments and environment.
+	 */
+	error = copyout(stringp, (void *)ustringp,
+	    ARG_MAX - imgp->args->stringspace);
+	if (error != 0)
+		return (error);
+
+	/*
+	 * Fill in "ps_strings" struct for ps, w, etc.
+	 */
+	imgp->argv = vectp;
+	if (suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp) != 0 ||
+	    suword32(&arginfo->ps_nargvstr, argc) != 0)
+		return (EFAULT);
+
+	/*
+	 * Fill in argument portion of vector table.
+	 */
+	for (; argc > 0; --argc) {
+		if (suword(vectp++, ustringp) != 0)
+			return (EFAULT);
+		while (*stringp++ != 0)
+			ustringp++;
+		ustringp++;
+	}
+
+	/* a null vector table pointer separates the argp's from the envp's */
+	if (suword(vectp++, 0) != 0)
+		return (EFAULT);
+
+	imgp->envv = vectp;
+	if (suword(&arginfo->ps_envstr, (long)(intptr_t)vectp) != 0 ||
+	    suword32(&arginfo->ps_nenvstr, envc) != 0)
+		return (EFAULT);
+
+	/*
+	 * Fill in environment portion of vector table.
+	 */
+	for (; envc > 0; --envc) {
+		if (suword(vectp++, ustringp) != 0)
+			return (EFAULT);
+		while (*stringp++ != 0)
+			ustringp++;
+		ustringp++;
+	}
+
+	/* end of vector table is a null pointer */
+	if (suword(vectp, 0) != 0)
+		return (EFAULT);
+
+	if (imgp->auxargs) {
+		vectp++;
+		error = imgp->sysent->sv_copyout_auxargs(imgp,
+		    (uintptr_t)vectp);
+		if (error != 0)
+			return (error);
+	}
+
+	return (0);
+}
diff --git a/sys/compat/linux/linux_elf.h b/sys/compat/linux/linux_elf.h
index 18d229d8481e..e0905983070b 100644
--- a/sys/compat/linux/linux_elf.h
+++ b/sys/compat/linux/linux_elf.h
@@ -38,5 +38,6 @@ struct note_info_list;
 
 void 	__linuxN(prepare_notes)(struct thread *, struct note_info_list *,
 	    size_t *);
+int	__linuxN(copyout_strings)(struct image_params *, uintptr_t *);
 
 #endif
diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c
index a4bbf8333f58..aaf52b873258 100644
--- a/sys/i386/linux/linux_sysvec.c
+++ b/sys/i386/linux/linux_sysvec.c
@@ -111,8 +111,6 @@ static void	linux_exec_setregs(struct thread *td,
 static void	linux_exec_sysvec_init(void *param);
 static int	linux_on_exec_vmspace(struct proc *p,
 		    struct image_params *imgp);
-static int	linux_copyout_strings(struct image_params *imgp,
-		    uintptr_t *stack_base);
 static void	linux_set_fork_retval(struct thread *td);
 static bool	linux_trans_osrel(const Elf_Note *note, int32_t *osrel);
 static void	linux_vdso_install(const void *param);
@@ -201,124 +199,6 @@ linux_copyout_auxargs(struct image_params *imgp, uintptr_t base)
 	return (error);
 }
 
-/*
- * Copied from kern/kern_exec.c
- */
-static int
-linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
-{
-	int argc, envc, error;
-	char **vectp;
-	char *stringp;
-	uintptr_t destp, ustringp;
-	struct ps_strings *arginfo;
-	char canary[LINUX_AT_RANDOM_LEN];
-	size_t execpath_len;
-	struct proc *p;
-
-	p = imgp->proc;
-	arginfo = (struct ps_strings *)PROC_PS_STRINGS(p);
-	destp = (uintptr_t)arginfo;
-
-	if (imgp->execpath != NULL && imgp->auxargs != NULL) {
-		execpath_len = strlen(imgp->execpath) + 1;
-		destp -= execpath_len;
-		destp = rounddown2(destp, sizeof(void *));
-		imgp->execpathp = (void *)destp;
-		error = copyout(imgp->execpath, imgp->execpathp, execpath_len);
-		if (error != 0)
-			return (error);
-	}
-
-	/* Prepare the canary for SSP. */
-	arc4rand(canary, sizeof(canary), 0);
-	destp -= roundup(sizeof(canary), sizeof(void *));
-	imgp->canary = (void *)destp;
-	error = copyout(canary, imgp->canary, sizeof(canary));
-	if (error != 0)
-		return (error);
-
-	/* Allocate room for the argument and environment strings. */
-	destp -= ARG_MAX - imgp->args->stringspace;
-	destp = rounddown2(destp, sizeof(void *));
-	ustringp = destp;
-
-	if (imgp->auxargs) {
-		/*
-		 * Allocate room on the stack for the ELF auxargs
-		 * array.  It has LINUX_AT_COUNT entries.
-		 */
-		destp -= LINUX_AT_COUNT * sizeof(Elf32_Auxinfo);
-		destp = rounddown2(destp, sizeof(void *));
-	}
-
-	vectp = (char **)destp;
-
-	/*
-	 * Allocate room for the argv[] and env vectors including the
-	 * terminating NULL pointers.
-	 */
-	vectp -= imgp->args->argc + 1 + imgp->args->envc + 1;
-
-	/* vectp also becomes our initial stack base. */
-	*stack_base = (uintptr_t)vectp;
-
-	stringp = imgp->args->begin_argv;
-	argc = imgp->args->argc;
-	envc = imgp->args->envc;
-
-	/* Copy out strings - arguments and environment. */
-	error = copyout(stringp, (void *)ustringp,
-	    ARG_MAX - imgp->args->stringspace);
-	if (error != 0)
-		return (error);
-
-	/* Fill in "ps_strings" struct for ps, w, etc. */
-	if (suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp) != 0 ||
-	    suword(&arginfo->ps_nargvstr, argc) != 0)
-		return (EFAULT);
-
-	/* Fill in argument portion of vector table. */
-	for (; argc > 0; --argc) {
-		if (suword(vectp++, ustringp) != 0)
-			return (EFAULT);
-		while (*stringp++ != 0)
-			ustringp++;
-		ustringp++;
-	}
-
-	/* A null vector table pointer separates the argp's from the envp's. */
-	if (suword(vectp++, 0) != 0)
-		return (EFAULT);
-
-	if (suword(&arginfo->ps_envstr, (long)(intptr_t)vectp) != 0 ||
-	    suword(&arginfo->ps_nenvstr, envc) != 0)
-		return (EFAULT);
-
-	/* Fill in environment portion of vector table. */
-	for (; envc > 0; --envc) {
-		if (suword(vectp++, ustringp) != 0)
-			return (EFAULT);
-		while (*stringp++ != 0)
-			ustringp++;
-		ustringp++;
-	}
-
-	/* The end of the vector table is a null pointer. */
-	if (suword(vectp, 0) != 0)
-		return (EFAULT);
-
-	if (imgp->auxargs) {
-		vectp++;
-		error = imgp->sysent->sv_copyout_auxargs(imgp,
-		    (uintptr_t)vectp);
-		if (error != 0)
-			return (error);
-	}
-
-	return (0);
-}
-
 static void
 linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 {
@@ -804,7 +684,7 @@ struct sysentvec elf_linux_sysvec = {
 	.sv_psstringssz	= sizeof(struct ps_strings),
 	.sv_stackprot	= VM_PROT_ALL,
 	.sv_copyout_auxargs = linux_copyout_auxargs,
-	.sv_copyout_strings = linux_copyout_strings,
+	.sv_copyout_strings = __linuxN(copyout_strings),
 	.sv_setregs	= linux_exec_setregs,
 	.sv_fixlimit	= NULL,
 	.sv_maxssiz	= NULL,