From: Christoph Hellwig <hch@lst.de>
To: Al Viro <viro@zeniv.linux.org.uk>
Cc: Arnd Bergmann <arnd@arndb.de>, Brian Gerst <brgerst@gmail.com>,
Luis Chamberlain <mcgrof@kernel.org>,
linux-arm-kernel@lists.infradead.org, x86@kernel.org,
linux-mips@vger.kernel.org, linux-parisc@vger.kernel.org,
linuxppc-dev@lists.ozlabs.org, linux-s390@vger.kernel.org,
sparclinux@vger.kernel.org, linux-fsdevel@vger.kernel.org,
linux-arch@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 5/6] exec: add a kernel_execveat helper
Date: Thu, 18 Jun 2020 16:46:26 +0200 [thread overview]
Message-ID: <20200618144627.114057-6-hch@lst.de> (raw)
In-Reply-To: <20200618144627.114057-1-hch@lst.de>
Add a kernel_execveat helper to execute a binary with kernel space argv
and envp pointers. Switch executing init and user mode helpers to this
new helper instead of relying on the implicit set_fs(KERNEL_DS) for early
init code and kernel threads, and move the getname call into the
do_execve helper.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/exec.c | 109 ++++++++++++++++++++++++++++++++--------
include/linux/binfmts.h | 6 +--
init/main.c | 6 +--
kernel/umh.c | 8 ++-
4 files changed, 95 insertions(+), 34 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c
index 34781db6bf6889..7923b8334ae600 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -435,6 +435,21 @@ static int count_strings(const char __user *const __user *argv)
return i;
}
+static int count_kernel_strings(const char *const *argv)
+{
+ int i;
+
+ if (!argv)
+ return 0;
+
+ for (i = 0; argv[i]; i++) {
+ if (i >= MAX_ARG_STRINGS)
+ return -E2BIG;
+ }
+
+ return i;
+}
+
static int check_arg_limit(struct linux_binprm *bprm)
{
unsigned long limit, ptr_size;
@@ -611,6 +626,19 @@ int copy_string_kernel(const char *arg, struct linux_binprm *bprm)
}
EXPORT_SYMBOL(copy_string_kernel);
+static int copy_strings_kernel(int argc, const char *const *argv,
+ struct linux_binprm *bprm)
+{
+ int ret;
+
+ while (argc-- > 0) {
+ ret = copy_string_kernel(argv[argc], bprm);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
#ifdef CONFIG_MMU
/*
@@ -1793,9 +1821,11 @@ static int exec_binprm(struct linux_binprm *bprm)
return 0;
}
-int do_execveat(int fd, struct filename *filename,
+static int __do_execveat(int fd, struct filename *filename,
const char __user *const __user *argv,
const char __user *const __user *envp,
+ const char *const *kernel_argv,
+ const char *const *kernel_envp,
int flags, struct file *file)
{
char *pathbuf = NULL;
@@ -1876,16 +1906,30 @@ int do_execveat(int fd, struct filename *filename,
if (retval)
goto out_unmark;
- bprm->argc = count_strings(argv);
- if (bprm->argc < 0) {
- retval = bprm->argc;
- goto out;
- }
+ if (unlikely(kernel_argv)) {
+ bprm->argc = count_kernel_strings(kernel_argv);
+ if (bprm->argc < 0) {
+ retval = bprm->argc;
+ goto out;
+ }
- bprm->envc = count_strings(envp);
- if (bprm->envc < 0) {
- retval = bprm->envc;
- goto out;
+ bprm->envc = count_kernel_strings(kernel_envp);
+ if (bprm->envc < 0) {
+ retval = bprm->envc;
+ goto out;
+ }
+ } else {
+ bprm->argc = count_strings(argv);
+ if (bprm->argc < 0) {
+ retval = bprm->argc;
+ goto out;
+ }
+
+ bprm->envc = count_strings(envp);
+ if (bprm->envc < 0) {
+ retval = bprm->envc;
+ goto out;
+ }
}
retval = check_arg_limit(bprm);
@@ -1902,13 +1946,22 @@ int do_execveat(int fd, struct filename *filename,
goto out;
bprm->exec = bprm->p;
- retval = copy_strings(bprm->envc, envp, bprm);
- if (retval < 0)
- goto out;
- retval = copy_strings(bprm->argc, argv, bprm);
- if (retval < 0)
- goto out;
+ if (unlikely(kernel_argv)) {
+ retval = copy_strings_kernel(bprm->envc, kernel_envp, bprm);
+ if (retval < 0)
+ goto out;
+ retval = copy_strings_kernel(bprm->argc, kernel_argv, bprm);
+ if (retval < 0)
+ goto out;
+ } else {
+ retval = copy_strings(bprm->envc, envp, bprm);
+ if (retval < 0)
+ goto out;
+ retval = copy_strings(bprm->argc, argv, bprm);
+ if (retval < 0)
+ goto out;
+ }
retval = exec_binprm(bprm);
if (retval < 0)
@@ -1959,6 +2012,23 @@ int do_execveat(int fd, struct filename *filename,
return retval;
}
+static int do_execveat(int fd, const char *filename,
+ const char __user *const __user *argv,
+ const char __user *const __user *envp, int flags)
+{
+ int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
+ struct filename *name = getname_flags(filename, lookup_flags, NULL);
+
+ return __do_execveat(fd, name, argv, envp, NULL, NULL, flags, NULL);
+}
+
+int kernel_execveat(int fd, const char *filename, const char *const *argv,
+ const char *const *envp, int flags, struct file *file)
+{
+ return __do_execveat(fd, getname_kernel(filename), NULL, NULL, argv,
+ envp, flags, file);
+}
+
void set_binfmt(struct linux_binfmt *new)
{
struct mm_struct *mm = current->mm;
@@ -1988,7 +2058,7 @@ SYSCALL_DEFINE3(execve,
const char __user *const __user *, argv,
const char __user *const __user *, envp)
{
- return do_execveat(AT_FDCWD, getname(filename), argv, envp, 0, NULL);
+ return do_execveat(AT_FDCWD, filename, argv, envp, 0);
}
SYSCALL_DEFINE5(execveat,
@@ -1997,8 +2067,5 @@ SYSCALL_DEFINE5(execveat,
const char __user *const __user *, envp,
int, flags)
{
- int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
- struct filename *name = getname_flags(filename, lookup_flags, NULL);
-
- return do_execveat(fd, name, argv, envp, flags, NULL);
+ return do_execveat(fd, filename, argv, envp, flags);
}
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index bed702e4b1fbd9..1e61c980c16354 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -134,9 +134,7 @@ int copy_string_kernel(const char *arg, struct linux_binprm *bprm);
extern void set_binfmt(struct linux_binfmt *new);
extern ssize_t read_code(struct file *, unsigned long, loff_t, size_t);
-int do_execveat(int fd, struct filename *filename,
- const char __user *const __user *__argv,
- const char __user *const __user *__envp,
- int flags, struct file *file);
+int kernel_execveat(int fd, const char *filename, const char *const *argv,
+ const char *const *envp, int flags, struct file *file);
#endif /* _LINUX_BINFMTS_H */
diff --git a/init/main.c b/init/main.c
index 838950ea7bca22..33de235dc2aa00 100644
--- a/init/main.c
+++ b/init/main.c
@@ -1329,10 +1329,8 @@ static int run_init_process(const char *init_filename)
pr_debug(" with environment:\n");
for (p = envp_init; *p; p++)
pr_debug(" %s\n", *p);
- return do_execveat(AT_FDCWD, getname_kernel(init_filename),
- (const char __user *const __user *)argv_init,
- (const char __user *const __user *)envp_init,
- 0, NULL);
+ return kernel_execveat(AT_FDCWD, init_filename, argv_init, envp_init, 0,
+ NULL);
}
static int try_to_run_init_process(const char *init_filename)
diff --git a/kernel/umh.c b/kernel/umh.c
index 7aa9a5817582ca..1284823dbad338 100644
--- a/kernel/umh.c
+++ b/kernel/umh.c
@@ -103,11 +103,9 @@ static int call_usermodehelper_exec_async(void *data)
commit_creds(new);
sub_info->pid = task_pid_nr(current);
- retval = do_execveat(AT_FDCWD,
- sub_info->path ? getname_kernel(sub_info->path) : NULL,
- (const char __user *const __user *)sub_info->argv,
- (const char __user *const __user *)sub_info->envp,
- 0, sub_info->file);
+ retval = kernel_execveat(AT_FDCWD, sub_info->path,
+ (const char *const *)sub_info->argv,
+ (const char *const *)sub_info->envp, 0, sub_info->file);
if (sub_info->file && !retval)
current->flags |= PF_UMH;
out:
--
2.26.2
next prev parent reply other threads:[~2020-06-18 14:47 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-06-18 14:46 properly support exec and wait with kernel pointers v2 Christoph Hellwig
2020-06-18 14:46 ` [PATCH 1/6] exec: cleanup the execve wrappers Christoph Hellwig
2020-06-18 14:46 ` [PATCH 2/6] exec: simplify the compat syscall handling Christoph Hellwig
2020-06-18 14:46 ` [PATCH 3/6] exec: cleanup the count() function Christoph Hellwig
2020-06-19 8:28 ` Sergei Shtylyov
2020-06-18 14:46 ` [PATCH 4/6] exec: split prepare_arg_pages Christoph Hellwig
2020-06-18 14:46 ` Christoph Hellwig [this message]
2020-06-18 14:46 ` [PATCH 6/6] kernel: add a kernel_wait helper Christoph Hellwig
2020-06-19 21:17 ` Luis Chamberlain
2020-06-20 6:35 ` Christoph Hellwig
2020-06-20 17:02 ` Luis Chamberlain
-- strict thread matches above, loose matches on Subject: below --
2020-06-15 13:00 properly support exec and wait with kernel pointers Christoph Hellwig
2020-06-15 13:00 ` [PATCH 5/6] exec: add a kernel_execveat helper Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200618144627.114057-6-hch@lst.de \
--to=hch@lst.de \
--cc=arnd@arndb.de \
--cc=brgerst@gmail.com \
--cc=linux-arch@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mips@vger.kernel.org \
--cc=linux-parisc@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=mcgrof@kernel.org \
--cc=sparclinux@vger.kernel.org \
--cc=viro@zeniv.linux.org.uk \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).