From patchwork Wed Jul 20 19:22:35 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 9240331 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 2B904600CB for ; Wed, 20 Jul 2016 19:24:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1C40927C2C for ; Wed, 20 Jul 2016 19:24:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 10FAC27D64; Wed, 20 Jul 2016 19:24:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 87D2227C2C for ; Wed, 20 Jul 2016 19:24:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755086AbcGTTX3 (ORCPT ); Wed, 20 Jul 2016 15:23:29 -0400 Received: from alt32.smtp-out.videotron.ca ([24.53.0.21]:43405 "EHLO alt32.smtp-out.videotron.ca" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754700AbcGTTWu (ORCPT ); Wed, 20 Jul 2016 15:22:50 -0400 Received: from yoda.home ([96.23.157.65]) by Videotron with SMTP id Px4xbSuz0YOXTPx4ybDLKw; Wed, 20 Jul 2016 15:22:48 -0400 X-Authority-Analysis: v=2.1 cv=Gfm35VjL c=1 sm=1 tr=0 a=keA3yYpnlypCNW5BNWqu+w==:117 a=keA3yYpnlypCNW5BNWqu+w==:17 a=L9H7d07YOLsA:10 a=9cW_t1CCXrUA:10 a=s5jvgZ67dGcA:10 a=cAmyUtKerLwA:10 a=KKAkSRfTAAAA:8 a=tBb2bbeoAAAA:8 a=SjwPGEeTKsiiQuiMm4kA:9 a=cvBusfyB2V15izCimMoJ:22 a=Oj-tNtZlA1e06AYgeCfH:22 Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id A432F2DA0660; Wed, 20 Jul 2016 15:22:45 -0400 (EDT) From: Nicolas Pitre To: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Alexander Viro , David Howells , Greg Ungerer Subject: [PATCH v4 06/12] binfmt_flat: clean up create_flat_tables() and stack accesses Date: Wed, 20 Jul 2016 15:22:35 -0400 Message-Id: <1469042561-7360-7-git-send-email-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1469042561-7360-1-git-send-email-nicolas.pitre@linaro.org> References: <1469042561-7360-1-git-send-email-nicolas.pitre@linaro.org> X-CMAE-Envelope: MS4wfIEkx2lqpLUL0yWfyNLRfTp6Xvt4KdjpFLkNtvVYclvB3Zwc2z4sVGU09FtvXF8W5whvpp9dT8bCMkRSxwq18+3f5zADKf6A+1DW5AWbE9WEJVDGDfFu 2X+6oIt/b6+z7K+dNHY/hCB3YLxwnpgN11r1nFdRUqsUGfl0egFHbYKaJcmYsQwGtwirm28Ictv5JFGI3/VoCduemMqx0QMH3JEEn2OEAAErheQXUylE2Ru/ nHibSCVpBTBlg/98EmrEeocWEk//whQAC0MpwlQg1FXMCgTZzjEzFCc7fMUcmfPZB6FXkAFAGVWYzbKoml6Ceg== Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 Reviewed-by: Greg Ungerer --- 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 a002e1a3b9..5dc7968a42 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -103,50 +103,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; } /****************************************************************************/ @@ -846,7 +854,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; @@ -860,11 +868,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) @@ -882,16 +889,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, ¤t->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). @@ -902,15 +911,15 @@ 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); #endif