linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Nicolas Pitre <nicolas.pitre@linaro.org>
To: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: Alexander Viro <viro@zeniv.linux.org.uk>,
	David Howells <dhowells@redhat.com>,
	Greg Ungerer <gerg@linux-m68k.org>
Subject: [PATCH v3 06/12] binfmt_flat: clean up create_flat_tables() and stack accesses
Date: Wed, 20 Jul 2016 00:20:18 -0400	[thread overview]
Message-ID: <1468988424-32671-7-git-send-email-nicolas.pitre@linaro.org> (raw)
In-Reply-To: <1468988424-32671-1-git-send-email-nicolas.pitre@linaro.org>

In addition to better code clarity, this brings proper usage of
user memory accessors everywhere the stack is touched. This is essential
for making this work on MMU systems.

Signed-off-by: Nicolas Pitre <nico@linaro.org>
Reviewed-by: Greg Ungerer <gerg@linux-m68k.org>
---
 fs/binfmt_flat.c | 117 ++++++++++++++++++++++++++++++-------------------------
 1 file changed, 63 insertions(+), 54 deletions(-)

diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index fdd33ba9e3..90a10d7149 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -107,50 +107,58 @@ static int flat_core_dump(struct coredump_params *cprm)
 /*
  * create_flat_tables() parses the env- and arg-strings in new user
  * memory and creates the pointer tables from them, and puts their
- * addresses on the "stack", returning the new stack pointer value.
+ * addresses on the "stack", recording the new stack pointer value.
  */
 
-static unsigned long create_flat_tables(
-	unsigned long pp,
-	struct linux_binprm * bprm)
+static int create_flat_tables(struct linux_binprm * bprm, unsigned long arg_start)
 {
-	unsigned long *argv,*envp;
-	unsigned long * sp;
-	char * p = (char*)pp;
-	int argc = bprm->argc;
-	int envc = bprm->envc;
-	char uninitialized_var(dummy);
-
-	sp = (unsigned long *)p;
-	sp -= (envc + argc + 2) + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
-	sp = (unsigned long *) ((unsigned long)sp & -FLAT_STACK_ALIGN);
-	argv = sp + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
-	envp = argv + (argc + 1);
+	char __user *p;
+	unsigned long __user *sp;
+	long i, len;
 
+	p = (char __user *)arg_start;
+	sp = (unsigned long __user *)current->mm->start_stack;
+
+	sp -= bprm->envc + 1;
+	sp -= bprm->argc + 1;
+	sp -= flat_argvp_envp_on_stack() ? 2 : 0;
+	sp -= 1;  /* &argc */
+
+	current->mm->start_stack = (unsigned long)sp & -FLAT_STACK_ALIGN;
+	sp = (unsigned long __user *)current->mm->start_stack;
+
+	__put_user(bprm->argc, sp++);
 	if (flat_argvp_envp_on_stack()) {
-		put_user((unsigned long) envp, sp + 2);
-		put_user((unsigned long) argv, sp + 1);
-	}
-
-	put_user(argc, sp);
-	current->mm->arg_start = (unsigned long) p;
-	while (argc-->0) {
-		put_user((unsigned long) p, argv++);
-		do {
-			get_user(dummy, p); p++;
-		} while (dummy);
-	}
-	put_user((unsigned long) NULL, argv);
-	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
-	while (envc-->0) {
-		put_user((unsigned long)p, envp); envp++;
-		do {
-			get_user(dummy, p); p++;
-		} while (dummy);
-	}
-	put_user((unsigned long) NULL, envp);
-	current->mm->env_end = (unsigned long) p;
-	return (unsigned long)sp;
+		unsigned long argv, envp;
+		argv = (unsigned long)(sp + 2);
+		envp = (unsigned long)(sp + 2 + bprm->argc + 1);
+		__put_user(argv, sp++);
+		__put_user(envp, sp++);
+	}
+
+	current->mm->arg_start = (unsigned long)p;
+	for (i = bprm->argc; i > 0; i--) {
+		__put_user((unsigned long)p, sp++);
+		len = strnlen_user(p, MAX_ARG_STRLEN);
+		if (!len || len > MAX_ARG_STRLEN)
+			return -EINVAL;
+		p += len;
+	}
+	__put_user(0, sp++);
+	current->mm->arg_end = (unsigned long)p;
+
+	current->mm->env_start = (unsigned long) p;
+	for (i = bprm->envc; i > 0; i--) {
+		__put_user((unsigned long)p, sp++);
+		len = strnlen_user(p, MAX_ARG_STRLEN);
+		if (!len || len > MAX_ARG_STRLEN)
+			return -EINVAL;
+		p += len;
+	}
+	__put_user(0, sp++);
+	current->mm->env_end = (unsigned long)p;
+
+	return 0;
 }
 
 /****************************************************************************/
@@ -849,7 +857,7 @@ static int load_flat_binary(struct linux_binprm * bprm)
 {
 	struct lib_info libinfo;
 	struct pt_regs *regs = current_pt_regs();
-	unsigned long sp, stack_len;
+	unsigned long stack_len;
 	unsigned long start_addr;
 	int res;
 	int i, j;
@@ -863,11 +871,10 @@ static int load_flat_binary(struct linux_binprm * bprm)
 	 * pedantic and include space for the argv/envp array as it may have
 	 * a lot of entries.
 	 */
-#define TOP_OF_ARGS (PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *))
-	stack_len = TOP_OF_ARGS - bprm->p;             /* the strings */
-	stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */
-	stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */
-	stack_len += FLAT_STACK_ALIGN - 1;  /* reserve for upcoming alignment */
+	stack_len = PAGE_SIZE * MAX_ARG_PAGES - bprm->p;  /* the strings */
+	stack_len += (bprm->argc + 1) * sizeof(char *);   /* the argv array */
+	stack_len += (bprm->envc + 1) * sizeof(char *);   /* the envp array */
+	stack_len = ALIGN(stack_len, FLAT_STACK_ALIGN);
 	
 	res = load_flat_file(bprm, &libinfo, 0, &stack_len);
 	if (res < 0)
@@ -885,16 +892,18 @@ static int load_flat_binary(struct linux_binprm * bprm)
 
 	set_binfmt(&flat_format);
 
-	sp = ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4;
-	pr_debug("sp=%lx\n", sp);
+	/* Stash our initial stack pointer into the mm structure */
+	current->mm->start_stack =
+		((current->mm->context.end_brk + stack_len + 3) & ~3) - 4;
+	pr_debug("sp=%lx\n", current->mm->start_stack);
 
 	/* copy the arg pages onto the stack */
-	res = transfer_args_to_stack(bprm, &sp);
+	res = transfer_args_to_stack(bprm, &current->mm->start_stack);
+	if (!res)
+		res = create_flat_tables(bprm, current->mm->start_stack);
 	if (res)
 		return res;
 
-	sp = create_flat_tables(sp, bprm);
-	
 	/* Fake some return addresses to ensure the call chain will
 	 * initialise library in order for us.  We are required to call
 	 * lib 1 first, then 2, ... and finally the main program (id 0).
@@ -905,14 +914,14 @@ static int load_flat_binary(struct linux_binprm * bprm)
 	for (i = MAX_SHARED_LIBS-1; i>0; i--) {
 		if (libinfo.lib_list[i].loaded) {
 			/* Push previos first to call address */
-			--sp;	put_user(start_addr, (unsigned long *)sp);
+			unsigned long __user *sp;
+			current->mm->start_stack -= sizeof(unsigned long);
+			sp = (unsigned long __user *)current->mm->start_stack;
+			__put_user(start_addr, sp);
 			start_addr = libinfo.lib_list[i].entry;
 		}
 	}
 #endif
-	
-	/* Stash our initial stack pointer into the mm structure */
-	current->mm->start_stack = sp;
 
 #ifdef FLAT_PLAT_INIT
 	FLAT_PLAT_INIT(regs);
-- 
2.7.4


  parent reply	other threads:[~2016-07-20  4:20 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-20  4:20 [PATCH v3 00/12] allow BFLT executables on systems with a MMU Nicolas Pitre
2016-07-20  4:20 ` [PATCH v3 01/12] binfmt_flat: assorted cleanups Nicolas Pitre
2016-07-20  4:20 ` [PATCH v3 02/12] binfmt_flat: convert printk invocations to their modern form Nicolas Pitre
2016-07-20  4:30   ` Joe Perches
2016-07-20  5:05     ` Nicolas Pitre
2016-07-20  4:20 ` [PATCH v3 03/12] binfmt_flat: prevent kernel dammage from corrupted executable headers Nicolas Pitre
2016-07-20  4:20 ` [PATCH v3 04/12] elf_fdpic_transfer_args_to_stack(): make it generic Nicolas Pitre
2016-07-20  4:20 ` [PATCH v3 05/12] binfmt_flat: use generic transfer_args_to_stack() Nicolas Pitre
2016-07-20  4:20 ` Nicolas Pitre [this message]
2016-07-20  4:20 ` [PATCH v3 07/12] binfmt_flat: use proper user space accessors with relocs processing code Nicolas Pitre
2016-07-20  4:20 ` [PATCH v3 08/12] binfmt_flat: use proper user space accessors with old relocs code Nicolas Pitre
2016-07-20  4:20 ` [PATCH v3 09/12] binfmt_flat: use clear_user() rather than memset() to clear .bss Nicolas Pitre
2016-07-20  7:15   ` Greg Ungerer
2016-07-20  4:20 ` [PATCH v3 10/12] binfmt_flat: update libraries' data segment pointer with userspace accessors Nicolas Pitre
2016-07-20  4:20 ` [PATCH v3 11/12] binfmt_flat: add MMU-specific support Nicolas Pitre
2016-07-20  4:20 ` [PATCH v3 12/12] binfmt_flat: allow compressed flat binary format to work on MMU systems Nicolas Pitre

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=1468988424-32671-7-git-send-email-nicolas.pitre@linaro.org \
    --to=nicolas.pitre@linaro.org \
    --cc=dhowells@redhat.com \
    --cc=gerg@linux-m68k.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    /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).