aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Chagin <dchagin@FreeBSD.org>2023-05-29 09:18:16 +0000
committerDmitry Chagin <dchagin@FreeBSD.org>2023-05-29 09:18:16 +0000
commit8340b03425cfa61ec17ad6a9b576590df3afd509 (patch)
tree44971fa6896dc74de58dda97f81de869647ab42c
parent07c0b6e535c5c5bdbbb562a04e21a1a4d039b942 (diff)
downloadsrc-8340b03425cfa61ec17ad6a9b576590df3afd509.tar.gz
src-8340b03425cfa61ec17ad6a9b576590df3afd509.zip
linux(4): Add a dedicated linux_exec_copyin_args()
Because Linux allows to exec binaries with 0 argc. Reviewed by: brooks Differential Revision: https://reviews.freebsd.org/D40148 MFC after: 2 month
-rw-r--r--sys/amd64/linux/syscalls.master4
-rw-r--r--sys/amd64/linux32/linux32_machdep.c14
-rw-r--r--sys/amd64/linux32/syscalls.master4
-rw-r--r--sys/arm64/linux/syscalls.master4
-rw-r--r--sys/compat/linux/linux_misc.c87
-rw-r--r--sys/i386/linux/syscalls.master4
6 files changed, 92 insertions, 25 deletions
diff --git a/sys/amd64/linux/syscalls.master b/sys/amd64/linux/syscalls.master
index 420c029fa892..e4ac2ef99edf 100644
--- 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
index 4e5d6eb55fc6..bcbf51082c64 100644
--- a/sys/amd64/linux32/linux32_machdep.c
+++ b/sys/amd64/linux32/linux32_machdep.c
@@ -114,20 +114,6 @@ linux_copyout_rusage(struct rusage *ru, void *uaddr)
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
index 777ffd865b8b..382b681fdde1 100644
--- 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
index 2a564f0e3c5d..b9dda787389c 100644
--- 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
index b5d48d106be6..583cc25f1c43 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -2555,7 +2555,89 @@ linux_seccomp(struct thread *td, struct linux_seccomp_args *args)
}
}
-#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_execve(struct thread *td, struct linux_execve_args *args)
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
index 9175bcd45dcf..c7168f7da80e 100644
--- 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 {