From patchwork Tue Jul 14 13:28:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Eric W. Biederman" X-Patchwork-Id: 11662859 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8CFAA1392 for ; Tue, 14 Jul 2020 13:31:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 75FE022280 for ; Tue, 14 Jul 2020 13:31:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727810AbgGNNbe (ORCPT ); Tue, 14 Jul 2020 09:31:34 -0400 Received: from out01.mta.xmission.com ([166.70.13.231]:48418 "EHLO out01.mta.xmission.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725997AbgGNNbd (ORCPT ); Tue, 14 Jul 2020 09:31:33 -0400 Received: from in02.mta.xmission.com ([166.70.13.52]) by out01.mta.xmission.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jvL1w-0007RF-BS; Tue, 14 Jul 2020 07:31:32 -0600 Received: from ip68-227-160-95.om.om.cox.net ([68.227.160.95] helo=x220.xmission.com) by in02.mta.xmission.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.87) (envelope-from ) id 1jvL1v-0006Xu-HX; Tue, 14 Jul 2020 07:31:32 -0600 From: ebiederm@xmission.com (Eric W. Biederman) To: Cc: Linus Torvalds , Kees Cook , Andy Lutomirski , "H. Peter Anvin" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Al Viro , Luis Chamberlain , , Tetsuo Handa , linux-security-module@vger.kernel.org, "Serge E. Hallyn" , James Morris , Kentaro Takeda , Casey Schaufler , John Johansen , Christoph Hellwig References: <871rle8bw2.fsf@x220.int.ebiederm.org> Date: Tue, 14 Jul 2020 08:28:42 -0500 In-Reply-To: <871rle8bw2.fsf@x220.int.ebiederm.org> (Eric W. Biederman's message of "Tue, 14 Jul 2020 08:27:41 -0500") Message-ID: <87v9iq6x9x.fsf@x220.int.ebiederm.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux) MIME-Version: 1.0 X-XM-SPF: eid=1jvL1v-0006Xu-HX;;;mid=<87v9iq6x9x.fsf@x220.int.ebiederm.org>;;;hst=in02.mta.xmission.com;;;ip=68.227.160.95;;;frm=ebiederm@xmission.com;;;spf=neutral X-XM-AID: U2FsdGVkX1+L9NFh+ZPsxXvjHVAolHu7lSRa9Zwp4L0= X-SA-Exim-Connect-IP: 68.227.160.95 X-SA-Exim-Mail-From: ebiederm@xmission.com X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on sa02.xmission.com X-Spam-Level: * X-Spam-Status: No, score=1.3 required=8.0 tests=ALL_TRUSTED,BAYES_50, DCC_CHECK_NEGATIVE,T_TooManySym_01,XMNoVowels autolearn=disabled version=3.4.2 X-Spam-Virus: No X-Spam-Report: * -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP * 0.8 BAYES_50 BODY: Bayes spam probability is 40 to 60% * [score: 0.5000] * 1.5 XMNoVowels Alpha-numberic number with no vowels * -0.0 DCC_CHECK_NEGATIVE Not listed in DCC * [sa02 0; Body=1 Fuz1=1 Fuz2=1] * 0.0 T_TooManySym_01 4+ unique symbols in subject X-Spam-DCC: ; sa02 0; Body=1 Fuz1=1 Fuz2=1 X-Spam-Combo: *; X-Spam-Relay-Country: X-Spam-Timing: total 436 ms - load_scoreonly_sql: 0.03 (0.0%), signal_user_changed: 3.7 (0.8%), b_tie_ro: 2.5 (0.6%), parse: 0.96 (0.2%), extract_message_metadata: 17 (3.9%), get_uri_detail_list: 1.21 (0.3%), tests_pri_-1000: 27 (6.1%), tests_pri_-950: 1.43 (0.3%), tests_pri_-900: 1.18 (0.3%), tests_pri_-90: 122 (27.9%), check_bayes: 119 (27.2%), b_tokenize: 9 (2.1%), b_tok_get_all: 6 (1.4%), b_comp_prob: 2.2 (0.5%), b_tok_touch_all: 98 (22.5%), b_finish: 0.66 (0.2%), tests_pri_0: 253 (58.0%), check_dkim_signature: 0.43 (0.1%), check_dkim_adsp: 2.3 (0.5%), poll_dns_idle: 0.55 (0.1%), tests_pri_10: 1.79 (0.4%), tests_pri_500: 6 (1.3%), rewrite_mail: 0.00 (0.0%) Subject: [PATCH 1/7] exec: Remove unnecessary spaces from binfmts.h X-Spam-Flag: No X-SA-Exim-Version: 4.2.1 (built Thu, 05 May 2016 13:38:54 -0600) X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org The general convention in the linux kernel is to define a pointer member as "type *name". The declaration of struct linux_binprm has several pointer defined as "type * name". Update them to the form of "type *name" for consistency. Suggested-by: Kees Cook Signed-off-by: "Eric W. Biederman" Reviewed-by: Kees Cook Reviewed-by: Christoph Hellwig --- include/linux/binfmts.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 7c27d7b57871..eb5cb8df5485 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -45,15 +45,15 @@ struct linux_binprm { #ifdef __alpha__ unsigned int taso:1; #endif - struct file * executable; /* Executable to pass to the interpreter */ - struct file * interpreter; - struct file * file; + struct file *executable; /* Executable to pass to the interpreter */ + struct file *interpreter; + struct file *file; struct cred *cred; /* new credentials */ int unsafe; /* how unsafe this exec is (mask of LSM_UNSAFE_*) */ unsigned int per_clear; /* bits to clear in current->personality */ int argc, envc; - const char * filename; /* Name of binary as seen by procps */ - const char * interp; /* Name of the binary really executed. Most + const char *filename; /* Name of binary as seen by procps */ + const char *interp; /* Name of the binary really executed. Most of the time same as filename, but could be different for binfmt_{misc,script} */ unsigned interp_flags; From patchwork Tue Jul 14 13:29:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Eric W. Biederman" X-Patchwork-Id: 11662863 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4732A1392 for ; Tue, 14 Jul 2020 13:32:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 37B6922280 for ; Tue, 14 Jul 2020 13:32:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728009AbgGNNb5 (ORCPT ); Tue, 14 Jul 2020 09:31:57 -0400 Received: from out01.mta.xmission.com ([166.70.13.231]:48594 "EHLO out01.mta.xmission.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725997AbgGNNb4 (ORCPT ); Tue, 14 Jul 2020 09:31:56 -0400 Received: from in01.mta.xmission.com ([166.70.13.51]) by out01.mta.xmission.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jvL2J-0007Tv-Ik; Tue, 14 Jul 2020 07:31:55 -0600 Received: from ip68-227-160-95.om.om.cox.net ([68.227.160.95] helo=x220.xmission.com) by in01.mta.xmission.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.87) (envelope-from ) id 1jvL2I-0005L6-SL; Tue, 14 Jul 2020 07:31:55 -0600 From: ebiederm@xmission.com (Eric W. Biederman) To: Cc: Linus Torvalds , Kees Cook , Andy Lutomirski , "H. Peter Anvin" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Al Viro , Luis Chamberlain , , Tetsuo Handa , linux-security-module@vger.kernel.org, "Serge E. Hallyn" , James Morris , Kentaro Takeda , Casey Schaufler , John Johansen , Christoph Hellwig References: <871rle8bw2.fsf@x220.int.ebiederm.org> Date: Tue, 14 Jul 2020 08:29:05 -0500 In-Reply-To: <871rle8bw2.fsf@x220.int.ebiederm.org> (Eric W. Biederman's message of "Tue, 14 Jul 2020 08:27:41 -0500") Message-ID: <87pn8y6x9a.fsf@x220.int.ebiederm.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux) MIME-Version: 1.0 X-XM-SPF: eid=1jvL2I-0005L6-SL;;;mid=<87pn8y6x9a.fsf@x220.int.ebiederm.org>;;;hst=in01.mta.xmission.com;;;ip=68.227.160.95;;;frm=ebiederm@xmission.com;;;spf=neutral X-XM-AID: U2FsdGVkX1/SB46uFkLNkWWJuV08LWp9w9461KO6n04= X-SA-Exim-Connect-IP: 68.227.160.95 X-SA-Exim-Mail-From: ebiederm@xmission.com X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on sa02.xmission.com X-Spam-Level: * X-Spam-Status: No, score=1.3 required=8.0 tests=ALL_TRUSTED,BAYES_50, DCC_CHECK_NEGATIVE,T_TooManySym_01,XMNoVowels autolearn=disabled version=3.4.2 X-Spam-Virus: No X-Spam-Report: * -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP * 0.8 BAYES_50 BODY: Bayes spam probability is 40 to 60% * [score: 0.4996] * 1.5 XMNoVowels Alpha-numberic number with no vowels * -0.0 DCC_CHECK_NEGATIVE Not listed in DCC * [sa02 0; Body=1 Fuz1=1 Fuz2=1] * 0.0 T_TooManySym_01 4+ unique symbols in subject X-Spam-DCC: ; sa02 0; Body=1 Fuz1=1 Fuz2=1 X-Spam-Combo: *; X-Spam-Relay-Country: X-Spam-Timing: total 369 ms - load_scoreonly_sql: 0.03 (0.0%), signal_user_changed: 3.5 (0.9%), b_tie_ro: 2.4 (0.6%), parse: 0.95 (0.3%), extract_message_metadata: 13 (3.4%), get_uri_detail_list: 1.52 (0.4%), tests_pri_-1000: 14 (3.8%), tests_pri_-950: 1.28 (0.3%), tests_pri_-900: 0.99 (0.3%), tests_pri_-90: 61 (16.5%), check_bayes: 59 (16.1%), b_tokenize: 10 (2.6%), b_tok_get_all: 8 (2.1%), b_comp_prob: 2.1 (0.6%), b_tok_touch_all: 37 (10.1%), b_finish: 0.57 (0.2%), tests_pri_0: 262 (71.1%), check_dkim_signature: 0.54 (0.1%), check_dkim_adsp: 2.2 (0.6%), poll_dns_idle: 0.70 (0.2%), tests_pri_10: 2.4 (0.6%), tests_pri_500: 7 (2.0%), rewrite_mail: 0.00 (0.0%) Subject: [PATCH 2/7] exec: Factor out alloc_bprm X-Spam-Flag: No X-SA-Exim-Version: 4.2.1 (built Thu, 05 May 2016 13:38:54 -0600) X-SA-Exim-Scanned: Yes (on in01.mta.xmission.com) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Currently it is necessary for the usermode helper code and the code that launches init to use set_fs so that pages coming from the kernel look like they are coming from userspace. To allow that usage of set_fs to be removed cleanly the argument copying from userspace needs to happen earlier. Move the allocation of the bprm into it's own function (alloc_bprm) and move the call of alloc_bprm before unshare_files so that bprm can ultimately be allocated, the arguments can be placed on the new stack, and then the bprm can be passed into the core of exec. Neither the allocation of struct binprm nor the unsharing depend upon each other so swapping the order in which they are called is trivially safe. To keep things consistent the order of cleanup at the end of do_execve_common swapped to match the order of initialization. Signed-off-by: "Eric W. Biederman" Reviewed-by: Kees Cook --- fs/exec.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 23dfbb820626..526156d6461d 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1560,6 +1560,14 @@ static void free_bprm(struct linux_binprm *bprm) kfree(bprm); } +static struct linux_binprm *alloc_bprm(void) +{ + struct linux_binprm *bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); + if (!bprm) + return ERR_PTR(-ENOMEM); + return bprm; +} + int bprm_change_interp(const char *interp, struct linux_binprm *bprm) { /* If a binfmt changed the interp, free it first. */ @@ -1848,18 +1856,19 @@ static int do_execveat_common(int fd, struct filename *filename, * further execve() calls fail. */ current->flags &= ~PF_NPROC_EXCEEDED; - retval = unshare_files(&displaced); - if (retval) + bprm = alloc_bprm(); + if (IS_ERR(bprm)) { + retval = PTR_ERR(bprm); goto out_ret; + } - retval = -ENOMEM; - bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); - if (!bprm) - goto out_files; + retval = unshare_files(&displaced); + if (retval) + goto out_free; retval = prepare_bprm_creds(bprm); if (retval) - goto out_free; + goto out_files; check_unsafe_exec(bprm); current->in_execve = 1; @@ -1956,13 +1965,13 @@ static int do_execveat_common(int fd, struct filename *filename, current->fs->in_exec = 0; current->in_execve = 0; +out_files: + if (displaced) + reset_files_struct(displaced); out_free: free_bprm(bprm); kfree(pathbuf); -out_files: - if (displaced) - reset_files_struct(displaced); out_ret: putname(filename); return retval; From patchwork Tue Jul 14 13:29:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Eric W. Biederman" X-Patchwork-Id: 11662867 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B481D1392 for ; Tue, 14 Jul 2020 13:32:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A11F2224B1 for ; Tue, 14 Jul 2020 13:32:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727863AbgGNNcu (ORCPT ); Tue, 14 Jul 2020 09:32:50 -0400 Received: from out01.mta.xmission.com ([166.70.13.231]:48882 "EHLO out01.mta.xmission.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725997AbgGNNct (ORCPT ); Tue, 14 Jul 2020 09:32:49 -0400 Received: from in01.mta.xmission.com ([166.70.13.51]) by out01.mta.xmission.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jvL2q-0007X5-Qj; Tue, 14 Jul 2020 07:32:28 -0600 Received: from ip68-227-160-95.om.om.cox.net ([68.227.160.95] helo=x220.xmission.com) by in01.mta.xmission.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.87) (envelope-from ) id 1jvL2n-0005PK-GW; Tue, 14 Jul 2020 07:32:26 -0600 From: ebiederm@xmission.com (Eric W. Biederman) To: Cc: Linus Torvalds , Kees Cook , Andy Lutomirski , "H. Peter Anvin" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Al Viro , Luis Chamberlain , , Tetsuo Handa , linux-security-module@vger.kernel.org, "Serge E. Hallyn" , James Morris , Kentaro Takeda , Casey Schaufler , John Johansen , Christoph Hellwig References: <871rle8bw2.fsf@x220.int.ebiederm.org> Date: Tue, 14 Jul 2020 08:29:36 -0500 In-Reply-To: <871rle8bw2.fsf@x220.int.ebiederm.org> (Eric W. Biederman's message of "Tue, 14 Jul 2020 08:27:41 -0500") Message-ID: <87k0z66x8f.fsf@x220.int.ebiederm.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux) MIME-Version: 1.0 X-XM-SPF: eid=1jvL2n-0005PK-GW;;;mid=<87k0z66x8f.fsf@x220.int.ebiederm.org>;;;hst=in01.mta.xmission.com;;;ip=68.227.160.95;;;frm=ebiederm@xmission.com;;;spf=neutral X-XM-AID: U2FsdGVkX1/bTuLU7Jd4S+t/5VVrYMEsOQfOiE6Q7Uk= X-SA-Exim-Connect-IP: 68.227.160.95 X-SA-Exim-Mail-From: ebiederm@xmission.com X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on sa05.xmission.com X-Spam-Level: ** X-Spam-Status: No, score=2.0 required=8.0 tests=ALL_TRUSTED,BAYES_50, DCC_CHECK_NEGATIVE,T_TooManySym_01,T_TooManySym_02,T_TooManySym_03, XMNoVowels,XMSubLong autolearn=disabled version=3.4.2 X-Spam-Report: * -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP * 0.8 BAYES_50 BODY: Bayes spam probability is 40 to 60% * [score: 0.4799] * 1.5 XMNoVowels Alpha-numberic number with no vowels * 0.7 XMSubLong Long Subject * -0.0 DCC_CHECK_NEGATIVE Not listed in DCC * [sa05 0; Body=1 Fuz1=1 Fuz2=1] * 0.0 T_TooManySym_02 5+ unique symbols in subject * 0.0 T_TooManySym_01 4+ unique symbols in subject * 0.0 T_TooManySym_03 6+ unique symbols in subject X-Spam-DCC: ; sa05 0; Body=1 Fuz1=1 Fuz2=1 X-Spam-Combo: **; X-Spam-Relay-Country: X-Spam-Timing: total 592 ms - load_scoreonly_sql: 0.08 (0.0%), signal_user_changed: 11 (1.9%), b_tie_ro: 10 (1.7%), parse: 1.18 (0.2%), extract_message_metadata: 11 (1.9%), get_uri_detail_list: 2.5 (0.4%), tests_pri_-1000: 13 (2.2%), tests_pri_-950: 1.10 (0.2%), tests_pri_-900: 0.86 (0.1%), tests_pri_-90: 174 (29.3%), check_bayes: 172 (29.1%), b_tokenize: 11 (1.9%), b_tok_get_all: 8 (1.4%), b_comp_prob: 2.6 (0.4%), b_tok_touch_all: 146 (24.7%), b_finish: 0.99 (0.2%), tests_pri_0: 364 (61.5%), check_dkim_signature: 0.95 (0.2%), check_dkim_adsp: 2.7 (0.5%), poll_dns_idle: 0.63 (0.1%), tests_pri_10: 1.89 (0.3%), tests_pri_500: 10 (1.7%), rewrite_mail: 0.00 (0.0%) Subject: [PATCH 3/7] exec: Move initialization of bprm->filename into alloc_bprm X-Spam-Flag: No X-SA-Exim-Version: 4.2.1 (built Thu, 05 May 2016 13:38:54 -0600) X-SA-Exim-Scanned: Yes (on in01.mta.xmission.com) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Currently it is necessary for the usermode helper code and the code that launches init to use set_fs so that pages coming from the kernel look like they are coming from userspace. To allow that usage of set_fs to be removed cleanly the argument copying from userspace needs to happen earlier. Move the computation of bprm->filename and possible allocation of a name in the case of execveat into alloc_bprm to make that possible. The exectuable name, the arguments, and the environment are copied into the new usermode stack which is stored in bprm until exec passes the point of no return. As the executable name is copied first onto the usermode stack it needs to be known. As there are no dependencies to computing the executable name, compute it early in alloc_bprm. As an implementation detail if the filename needs to be generated because it embeds a file descriptor store that filename in a new field bprm->fdpath, and free it in free_bprm. Previously this was done in an independent variable pathbuf. I have renamed pathbuf fdpath because fdpath is more suggestive of what kind of path is in the variable. I moved fdpath into struct linux_binprm because it is tightly tied to the other variables in struct linux_binprm, and as such is needed to allow the call alloc_binprm to move. Signed-off-by: "Eric W. Biederman" Reviewed-by: Kees Cook Reviewed-by: Christoph Hellwig --- fs/exec.c | 61 ++++++++++++++++++++++------------------- include/linux/binfmts.h | 1 + 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 526156d6461d..7e8af27dd199 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1557,15 +1557,37 @@ static void free_bprm(struct linux_binprm *bprm) /* If a binfmt changed the interp, free it. */ if (bprm->interp != bprm->filename) kfree(bprm->interp); + kfree(bprm->fdpath); kfree(bprm); } -static struct linux_binprm *alloc_bprm(void) +static struct linux_binprm *alloc_bprm(int fd, struct filename *filename) { struct linux_binprm *bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); + int retval = -ENOMEM; if (!bprm) - return ERR_PTR(-ENOMEM); + goto out; + + if (fd == AT_FDCWD || filename->name[0] == '/') { + bprm->filename = filename->name; + } else { + if (filename->name[0] == '\0') + bprm->fdpath = kasprintf(GFP_KERNEL, "/dev/fd/%d", fd); + else + bprm->fdpath = kasprintf(GFP_KERNEL, "/dev/fd/%d/%s", + fd, filename->name); + if (!bprm->fdpath) + goto out_free; + + bprm->filename = bprm->fdpath; + } + bprm->interp = bprm->filename; return bprm; + +out_free: + free_bprm(bprm); +out: + return ERR_PTR(retval); } int bprm_change_interp(const char *interp, struct linux_binprm *bprm) @@ -1831,7 +1853,6 @@ static int do_execveat_common(int fd, struct filename *filename, struct user_arg_ptr envp, int flags) { - char *pathbuf = NULL; struct linux_binprm *bprm; struct file *file; struct files_struct *displaced; @@ -1856,7 +1877,7 @@ static int do_execveat_common(int fd, struct filename *filename, * further execve() calls fail. */ current->flags &= ~PF_NPROC_EXCEEDED; - bprm = alloc_bprm(); + bprm = alloc_bprm(fd, filename); if (IS_ERR(bprm)) { retval = PTR_ERR(bprm); goto out_ret; @@ -1881,28 +1902,14 @@ static int do_execveat_common(int fd, struct filename *filename, sched_exec(); bprm->file = file; - if (fd == AT_FDCWD || filename->name[0] == '/') { - bprm->filename = filename->name; - } else { - if (filename->name[0] == '\0') - pathbuf = kasprintf(GFP_KERNEL, "/dev/fd/%d", fd); - else - pathbuf = kasprintf(GFP_KERNEL, "/dev/fd/%d/%s", - fd, filename->name); - if (!pathbuf) { - retval = -ENOMEM; - goto out_unmark; - } - /* - * Record that a name derived from an O_CLOEXEC fd will be - * inaccessible after exec. Relies on having exclusive access to - * current->files (due to unshare_files above). - */ - if (close_on_exec(fd, rcu_dereference_raw(current->files->fdt))) - bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE; - bprm->filename = pathbuf; - } - bprm->interp = bprm->filename; + /* + * Record that a name derived from an O_CLOEXEC fd will be + * inaccessible after exec. Relies on having exclusive access to + * current->files (due to unshare_files above). + */ + if (bprm->fdpath && + close_on_exec(fd, rcu_dereference_raw(current->files->fdt))) + bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE; retval = bprm_mm_init(bprm); if (retval) @@ -1941,7 +1948,6 @@ static int do_execveat_common(int fd, struct filename *filename, acct_update_integrals(current); task_numa_free(current, false); free_bprm(bprm); - kfree(pathbuf); putname(filename); if (displaced) put_files_struct(displaced); @@ -1970,7 +1976,6 @@ static int do_execveat_common(int fd, struct filename *filename, reset_files_struct(displaced); out_free: free_bprm(bprm); - kfree(pathbuf); out_ret: putname(filename); diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index eb5cb8df5485..8e9e1b0c8eb8 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -56,6 +56,7 @@ struct linux_binprm { const char *interp; /* Name of the binary really executed. Most of the time same as filename, but could be different for binfmt_{misc,script} */ + const char *fdpath; /* generated filename for execveat */ unsigned interp_flags; int execfd; /* File descriptor of the executable */ unsigned long loader, exec; From patchwork Tue Jul 14 13:30:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Eric W. Biederman" X-Patchwork-Id: 11662871 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 619291392 for ; Tue, 14 Jul 2020 13:33:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5198A22280 for ; Tue, 14 Jul 2020 13:33:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728143AbgGNNdA (ORCPT ); Tue, 14 Jul 2020 09:33:00 -0400 Received: from out01.mta.xmission.com ([166.70.13.231]:48954 "EHLO out01.mta.xmission.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725997AbgGNNc7 (ORCPT ); Tue, 14 Jul 2020 09:32:59 -0400 Received: from in02.mta.xmission.com ([166.70.13.52]) by out01.mta.xmission.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jvL3F-0007ZZ-1S; Tue, 14 Jul 2020 07:32:53 -0600 Received: from ip68-227-160-95.om.om.cox.net ([68.227.160.95] helo=x220.xmission.com) by in02.mta.xmission.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.87) (envelope-from ) id 1jvL3E-0006ij-1l; Tue, 14 Jul 2020 07:32:52 -0600 From: ebiederm@xmission.com (Eric W. Biederman) To: Cc: Linus Torvalds , Kees Cook , Andy Lutomirski , "H. Peter Anvin" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Al Viro , Luis Chamberlain , , Tetsuo Handa , linux-security-module@vger.kernel.org, "Serge E. Hallyn" , James Morris , Kentaro Takeda , Casey Schaufler , John Johansen , Christoph Hellwig References: <871rle8bw2.fsf@x220.int.ebiederm.org> Date: Tue, 14 Jul 2020 08:30:02 -0500 In-Reply-To: <871rle8bw2.fsf@x220.int.ebiederm.org> (Eric W. Biederman's message of "Tue, 14 Jul 2020 08:27:41 -0500") Message-ID: <87eepe6x7p.fsf@x220.int.ebiederm.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux) MIME-Version: 1.0 X-XM-SPF: eid=1jvL3E-0006ij-1l;;;mid=<87eepe6x7p.fsf@x220.int.ebiederm.org>;;;hst=in02.mta.xmission.com;;;ip=68.227.160.95;;;frm=ebiederm@xmission.com;;;spf=neutral X-XM-AID: U2FsdGVkX1/Tp8T+D0arIMZhfUhTvULP2xEom+axBvw= X-SA-Exim-Connect-IP: 68.227.160.95 X-SA-Exim-Mail-From: ebiederm@xmission.com X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on sa07.xmission.com X-Spam-Level: * X-Spam-Status: No, score=1.3 required=8.0 tests=ALL_TRUSTED,BAYES_50, DCC_CHECK_NEGATIVE,T_TooManySym_01,XMNoVowels autolearn=disabled version=3.4.2 X-Spam-Report: * -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP * 0.8 BAYES_50 BODY: Bayes spam probability is 40 to 60% * [score: 0.5000] * 1.5 XMNoVowels Alpha-numberic number with no vowels * -0.0 DCC_CHECK_NEGATIVE Not listed in DCC * [sa07 0; Body=1 Fuz1=1 Fuz2=1] * 0.0 T_TooManySym_01 4+ unique symbols in subject X-Spam-DCC: ; sa07 0; Body=1 Fuz1=1 Fuz2=1 X-Spam-Combo: *; X-Spam-Relay-Country: X-Spam-Timing: total 552 ms - load_scoreonly_sql: 0.04 (0.0%), signal_user_changed: 11 (2.0%), b_tie_ro: 10 (1.7%), parse: 0.98 (0.2%), extract_message_metadata: 12 (2.2%), get_uri_detail_list: 2.0 (0.4%), tests_pri_-1000: 16 (2.9%), tests_pri_-950: 1.31 (0.2%), tests_pri_-900: 1.08 (0.2%), tests_pri_-90: 86 (15.5%), check_bayes: 84 (15.2%), b_tokenize: 10 (1.8%), b_tok_get_all: 9 (1.6%), b_comp_prob: 2.7 (0.5%), b_tok_touch_all: 58 (10.5%), b_finish: 1.02 (0.2%), tests_pri_0: 413 (74.7%), check_dkim_signature: 0.59 (0.1%), check_dkim_adsp: 23 (4.1%), poll_dns_idle: 21 (3.8%), tests_pri_10: 2.2 (0.4%), tests_pri_500: 7 (1.2%), rewrite_mail: 0.00 (0.0%) Subject: [PATCH 4/7] exec: Move bprm_mm_init into alloc_bprm X-Spam-Flag: No X-SA-Exim-Version: 4.2.1 (built Thu, 05 May 2016 13:38:54 -0600) X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Currently it is necessary for the usermode helper code and the code that launches init to use set_fs so that pages coming from the kernel look like they are coming from userspace. To allow that usage of set_fs to be removed cleanly the argument copying from userspace needs to happen earlier. Move the allocation and initialization of bprm->mm into alloc_bprm so that the bprm->mm is available early to store the new user stack into. This is a prerequisite for copying argv and envp into the new user stack early before ther rest of exec. To keep the things consistent the cleanup of bprm->mm is moved into free_bprm. So that bprm->mm will be cleaned up whenever bprm->mm is allocated and free_bprm are called. Moving bprm_mm_init earlier is safe as it does not depend on any files, current->in_execve, current->fs->in_exec, bprm->unsafe, or the if the file table is shared. (AKA bprm_mm_init does not depend on any of the code that happens between alloc_bprm and where it was previously called.) This moves bprm->mm cleanup after current->fs->in_exec is set to 0. This is safe because current->fs->in_exec is only used to preventy taking an additional reference on the fs_struct. This moves bprm->mm cleanup after current->in_execve is set to 0. This is safe because current->in_execve is only used by the lsms (apparmor and tomoyou) and always for LSM specific functions, never for anything to do with the mm. This adds bprm->mm cleanup into the successful return path. This is safe because being on the successful return path implies that begin_new_exec succeeded and set brpm->mm to NULL. As bprm->mm is NULL bprm cleanup I am moving into free_bprm will do nothing. Signed-off-by: "Eric W. Biederman" Reviewed-by: Kees Cook Reviewed-by: Christoph Hellwig --- fs/exec.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 7e8af27dd199..afb168bf5e23 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1543,6 +1543,10 @@ static int prepare_bprm_creds(struct linux_binprm *bprm) static void free_bprm(struct linux_binprm *bprm) { + if (bprm->mm) { + acct_arg_size(bprm, 0); + mmput(bprm->mm); + } free_arg_pages(bprm); if (bprm->cred) { mutex_unlock(¤t->signal->cred_guard_mutex); @@ -1582,6 +1586,10 @@ static struct linux_binprm *alloc_bprm(int fd, struct filename *filename) bprm->filename = bprm->fdpath; } bprm->interp = bprm->filename; + + retval = bprm_mm_init(bprm); + if (retval) + goto out_free; return bprm; out_free: @@ -1911,10 +1919,6 @@ static int do_execveat_common(int fd, struct filename *filename, close_on_exec(fd, rcu_dereference_raw(current->files->fdt))) bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE; - retval = bprm_mm_init(bprm); - if (retval) - goto out_unmark; - retval = prepare_arg_pages(bprm, argv, envp); if (retval < 0) goto out; @@ -1962,10 +1966,6 @@ static int do_execveat_common(int fd, struct filename *filename, */ if (bprm->point_of_no_return && !fatal_signal_pending(current)) force_sigsegv(SIGSEGV); - if (bprm->mm) { - acct_arg_size(bprm, 0); - mmput(bprm->mm); - } out_unmark: current->fs->in_exec = 0; From patchwork Tue Jul 14 13:30:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Eric W. Biederman" X-Patchwork-Id: 11662873 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 393971392 for ; Tue, 14 Jul 2020 13:33:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 23780224D2 for ; Tue, 14 Jul 2020 13:33:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726384AbgGNNdX (ORCPT ); Tue, 14 Jul 2020 09:33:23 -0400 Received: from out03.mta.xmission.com ([166.70.13.233]:37604 "EHLO out03.mta.xmission.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725883AbgGNNdX (ORCPT ); Tue, 14 Jul 2020 09:33:23 -0400 Received: from in01.mta.xmission.com ([166.70.13.51]) by out03.mta.xmission.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jvL3h-0006vp-3b; Tue, 14 Jul 2020 07:33:21 -0600 Received: from ip68-227-160-95.om.om.cox.net ([68.227.160.95] helo=x220.xmission.com) by in01.mta.xmission.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.87) (envelope-from ) id 1jvL3f-0005XQ-Pc; Tue, 14 Jul 2020 07:33:20 -0600 From: ebiederm@xmission.com (Eric W. Biederman) To: Cc: Linus Torvalds , Kees Cook , Andy Lutomirski , "H. Peter Anvin" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Al Viro , Luis Chamberlain , , Tetsuo Handa , linux-security-module@vger.kernel.org, "Serge E. Hallyn" , James Morris , Kentaro Takeda , Casey Schaufler , John Johansen , Christoph Hellwig References: <871rle8bw2.fsf@x220.int.ebiederm.org> Date: Tue, 14 Jul 2020 08:30:30 -0500 In-Reply-To: <871rle8bw2.fsf@x220.int.ebiederm.org> (Eric W. Biederman's message of "Tue, 14 Jul 2020 08:27:41 -0500") Message-ID: <878sfm6x6x.fsf@x220.int.ebiederm.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux) MIME-Version: 1.0 X-XM-SPF: eid=1jvL3f-0005XQ-Pc;;;mid=<878sfm6x6x.fsf@x220.int.ebiederm.org>;;;hst=in01.mta.xmission.com;;;ip=68.227.160.95;;;frm=ebiederm@xmission.com;;;spf=neutral X-XM-AID: U2FsdGVkX1+OY/NvhT3MYjHsTJQkDJtTncWPgQJQ95w= X-SA-Exim-Connect-IP: 68.227.160.95 X-SA-Exim-Mail-From: ebiederm@xmission.com X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on sa08.xmission.com X-Spam-Level: ** X-Spam-Status: No, score=2.0 required=8.0 tests=ALL_TRUSTED,BAYES_50, DCC_CHECK_NEGATIVE,T_TooManySym_01,XMNoVowels,XMSubLong autolearn=disabled version=3.4.2 X-Spam-Report: * -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP * 0.8 BAYES_50 BODY: Bayes spam probability is 40 to 60% * [score: 0.4994] * 0.7 XMSubLong Long Subject * 1.5 XMNoVowels Alpha-numberic number with no vowels * -0.0 DCC_CHECK_NEGATIVE Not listed in DCC * [sa08 0; Body=1 Fuz1=1 Fuz2=1] * 0.0 T_TooManySym_01 4+ unique symbols in subject X-Spam-DCC: ; sa08 0; Body=1 Fuz1=1 Fuz2=1 X-Spam-Combo: **; X-Spam-Relay-Country: X-Spam-Timing: total 922 ms - load_scoreonly_sql: 0.05 (0.0%), signal_user_changed: 10 (1.1%), b_tie_ro: 9 (0.9%), parse: 1.81 (0.2%), extract_message_metadata: 19 (2.0%), get_uri_detail_list: 3.7 (0.4%), tests_pri_-1000: 24 (2.6%), tests_pri_-950: 2.5 (0.3%), tests_pri_-900: 2.2 (0.2%), tests_pri_-90: 184 (20.0%), check_bayes: 181 (19.7%), b_tokenize: 22 (2.4%), b_tok_get_all: 19 (2.0%), b_comp_prob: 4.3 (0.5%), b_tok_touch_all: 131 (14.2%), b_finish: 1.48 (0.2%), tests_pri_0: 663 (71.8%), check_dkim_signature: 0.78 (0.1%), check_dkim_adsp: 2.9 (0.3%), poll_dns_idle: 1.05 (0.1%), tests_pri_10: 2.1 (0.2%), tests_pri_500: 8 (0.8%), rewrite_mail: 0.00 (0.0%) Subject: [PATCH 5/7] exec: Factor bprm_execve out of do_execve_common X-Spam-Flag: No X-SA-Exim-Version: 4.2.1 (built Thu, 05 May 2016 13:38:54 -0600) X-SA-Exim-Scanned: Yes (on in01.mta.xmission.com) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Currently it is necessary for the usermode helper code and the code that launches init to use set_fs so that pages coming from the kernel look like they are coming from userspace. To allow that usage of set_fs to be removed cleanly the argument copying from userspace needs to happen earlier. Factor bprm_execve out of do_execve_common to separate out the copying of arguments to the newe stack, and the rest of exec. In separating bprm_execve from do_execve_common the copying of the arguments onto the new stack happens earlier. As the copying of the arguments does not depend any security hooks, files, the file table, current->in_execve, current->fs->in_exec, bprm->unsafe, or creds this is safe. Likewise the security hook security_creds_for_exec does not depend upon preventing the argument copying from happening. In addition to making it possible to implement kernel_execve that performs the copying differently, this separation of bprm_execve from do_execve_common makes for a nice separation of responsibilities making the exec code easier to navigate. Signed-off-by: "Eric W. Biederman" Reviewed-by: Kees Cook Reviewed-by: Christoph Hellwig --- fs/exec.c | 108 +++++++++++++++++++++++++++++------------------------- 1 file changed, 58 insertions(+), 50 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index afb168bf5e23..50508892fa71 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1856,44 +1856,16 @@ static int exec_binprm(struct linux_binprm *bprm) /* * sys_execve() executes a new program. */ -static int do_execveat_common(int fd, struct filename *filename, - struct user_arg_ptr argv, - struct user_arg_ptr envp, - int flags) +static int bprm_execve(struct linux_binprm *bprm, + int fd, struct filename *filename, int flags) { - struct linux_binprm *bprm; struct file *file; struct files_struct *displaced; int retval; - if (IS_ERR(filename)) - return PTR_ERR(filename); - - /* - * We move the actual failure in case of RLIMIT_NPROC excess from - * set*uid() to execve() because too many poorly written programs - * don't check setuid() return code. Here we additionally recheck - * whether NPROC limit is still exceeded. - */ - if ((current->flags & PF_NPROC_EXCEEDED) && - atomic_read(¤t_user()->processes) > rlimit(RLIMIT_NPROC)) { - retval = -EAGAIN; - goto out_ret; - } - - /* We're below the limit (still or again), so we don't want to make - * further execve() calls fail. */ - current->flags &= ~PF_NPROC_EXCEEDED; - - bprm = alloc_bprm(fd, filename); - if (IS_ERR(bprm)) { - retval = PTR_ERR(bprm); - goto out_ret; - } - retval = unshare_files(&displaced); if (retval) - goto out_free; + return retval; retval = prepare_bprm_creds(bprm); if (retval) @@ -1919,28 +1891,11 @@ static int do_execveat_common(int fd, struct filename *filename, close_on_exec(fd, rcu_dereference_raw(current->files->fdt))) bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE; - retval = prepare_arg_pages(bprm, argv, envp); - if (retval < 0) - goto out; - /* Set the unchanging part of bprm->cred */ retval = security_bprm_creds_for_exec(bprm); if (retval) goto out; - retval = copy_string_kernel(bprm->filename, bprm); - if (retval < 0) - 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; - retval = exec_binprm(bprm); if (retval < 0) goto out; @@ -1951,8 +1906,6 @@ static int do_execveat_common(int fd, struct filename *filename, rseq_execve(current); acct_update_integrals(current); task_numa_free(current, false); - free_bprm(bprm); - putname(filename); if (displaced) put_files_struct(displaced); return retval; @@ -1974,6 +1927,61 @@ static int do_execveat_common(int fd, struct filename *filename, out_files: if (displaced) reset_files_struct(displaced); + + return retval; +} + +static int do_execveat_common(int fd, struct filename *filename, + struct user_arg_ptr argv, + struct user_arg_ptr envp, + int flags) +{ + struct linux_binprm *bprm; + int retval; + + if (IS_ERR(filename)) + return PTR_ERR(filename); + + /* + * We move the actual failure in case of RLIMIT_NPROC excess from + * set*uid() to execve() because too many poorly written programs + * don't check setuid() return code. Here we additionally recheck + * whether NPROC limit is still exceeded. + */ + if ((current->flags & PF_NPROC_EXCEEDED) && + atomic_read(¤t_user()->processes) > rlimit(RLIMIT_NPROC)) { + retval = -EAGAIN; + goto out_ret; + } + + /* We're below the limit (still or again), so we don't want to make + * further execve() calls fail. */ + current->flags &= ~PF_NPROC_EXCEEDED; + + bprm = alloc_bprm(fd, filename); + if (IS_ERR(bprm)) { + retval = PTR_ERR(bprm); + goto out_ret; + } + + retval = prepare_arg_pages(bprm, argv, envp); + if (retval < 0) + goto out_free; + + retval = copy_string_kernel(bprm->filename, bprm); + if (retval < 0) + goto out_free; + bprm->exec = bprm->p; + + retval = copy_strings(bprm->envc, envp, bprm); + if (retval < 0) + goto out_free; + + retval = copy_strings(bprm->argc, argv, bprm); + if (retval < 0) + goto out_free; + + retval = bprm_execve(bprm, fd, filename, flags); out_free: free_bprm(bprm); From patchwork Tue Jul 14 13:31:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Eric W. Biederman" X-Patchwork-Id: 11662879 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DD5F01392 for ; Tue, 14 Jul 2020 13:34:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CD18D224B1 for ; Tue, 14 Jul 2020 13:34:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728387AbgGNNd4 (ORCPT ); Tue, 14 Jul 2020 09:33:56 -0400 Received: from out02.mta.xmission.com ([166.70.13.232]:52472 "EHLO out02.mta.xmission.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728049AbgGNNdz (ORCPT ); Tue, 14 Jul 2020 09:33:55 -0400 Received: from in01.mta.xmission.com ([166.70.13.51]) by out02.mta.xmission.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jvL4D-0002gA-MW; Tue, 14 Jul 2020 07:33:53 -0600 Received: from ip68-227-160-95.om.om.cox.net ([68.227.160.95] helo=x220.xmission.com) by in01.mta.xmission.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.87) (envelope-from ) id 1jvL4C-0005bi-PE; Tue, 14 Jul 2020 07:33:53 -0600 From: ebiederm@xmission.com (Eric W. Biederman) To: Cc: Linus Torvalds , Kees Cook , Andy Lutomirski , "H. Peter Anvin" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Al Viro , Luis Chamberlain , , Tetsuo Handa , linux-security-module@vger.kernel.org, "Serge E. Hallyn" , James Morris , Kentaro Takeda , Casey Schaufler , John Johansen , Christoph Hellwig References: <871rle8bw2.fsf@x220.int.ebiederm.org> Date: Tue, 14 Jul 2020 08:31:03 -0500 In-Reply-To: <871rle8bw2.fsf@x220.int.ebiederm.org> (Eric W. Biederman's message of "Tue, 14 Jul 2020 08:27:41 -0500") Message-ID: <87365u6x60.fsf@x220.int.ebiederm.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux) MIME-Version: 1.0 X-XM-SPF: eid=1jvL4C-0005bi-PE;;;mid=<87365u6x60.fsf@x220.int.ebiederm.org>;;;hst=in01.mta.xmission.com;;;ip=68.227.160.95;;;frm=ebiederm@xmission.com;;;spf=neutral X-XM-AID: U2FsdGVkX1+tYbnh3Q62SSMVnifjKF7zDyhQnXaMvYo= X-SA-Exim-Connect-IP: 68.227.160.95 X-SA-Exim-Mail-From: ebiederm@xmission.com X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on sa07.xmission.com X-Spam-Level: ** X-Spam-Status: No, score=2.0 required=8.0 tests=ALL_TRUSTED,BAYES_50, DCC_CHECK_NEGATIVE,T_TooManySym_01,XMNoVowels,XMSubLong autolearn=disabled version=3.4.2 X-Spam-Report: * -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP * 0.8 BAYES_50 BODY: Bayes spam probability is 40 to 60% * [score: 0.4989] * 0.7 XMSubLong Long Subject * 1.5 XMNoVowels Alpha-numberic number with no vowels * -0.0 DCC_CHECK_NEGATIVE Not listed in DCC * [sa07 0; Body=1 Fuz1=1 Fuz2=1] * 0.0 T_TooManySym_01 4+ unique symbols in subject X-Spam-DCC: ; sa07 0; Body=1 Fuz1=1 Fuz2=1 X-Spam-Combo: **; X-Spam-Relay-Country: X-Spam-Timing: total 416 ms - load_scoreonly_sql: 0.04 (0.0%), signal_user_changed: 11 (2.6%), b_tie_ro: 9 (2.3%), parse: 0.88 (0.2%), extract_message_metadata: 11 (2.6%), get_uri_detail_list: 1.18 (0.3%), tests_pri_-1000: 15 (3.5%), tests_pri_-950: 1.26 (0.3%), tests_pri_-900: 1.03 (0.2%), tests_pri_-90: 112 (26.9%), check_bayes: 110 (26.5%), b_tokenize: 8 (1.9%), b_tok_get_all: 7 (1.7%), b_comp_prob: 1.87 (0.5%), b_tok_touch_all: 90 (21.6%), b_finish: 0.96 (0.2%), tests_pri_0: 252 (60.6%), check_dkim_signature: 0.54 (0.1%), check_dkim_adsp: 2.4 (0.6%), poll_dns_idle: 0.72 (0.2%), tests_pri_10: 2.1 (0.5%), tests_pri_500: 7 (1.8%), rewrite_mail: 0.00 (0.0%) Subject: [PATCH 6/7] exec: Factor bprm_stack_limits out of prepare_arg_pages X-Spam-Flag: No X-SA-Exim-Version: 4.2.1 (built Thu, 05 May 2016 13:38:54 -0600) X-SA-Exim-Scanned: Yes (on in01.mta.xmission.com) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org In preparation for implementiong kernel_execve (which will take kernel pointers not userspace pointers) factor out bprm_stack_limits out of prepare_arg_pages. This separates the counting which depends upon the getting data from userspace from the calculations of the stack limits which is usable in kernel_execve. The remove prepare_args_pages and compute bprm->argc and bprm->envc directly in do_execveat_common, before bprm_stack_limits is called. Signed-off-by: "Eric W. Biederman" Reviewed-by: Kees Cook Reviewed-by: Christoph Hellwig --- fs/exec.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 50508892fa71..f8135dc149b3 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -448,19 +448,10 @@ static int count(struct user_arg_ptr argv, int max) return i; } -static int prepare_arg_pages(struct linux_binprm *bprm, - struct user_arg_ptr argv, struct user_arg_ptr envp) +static int bprm_stack_limits(struct linux_binprm *bprm) { unsigned long limit, ptr_size; - bprm->argc = count(argv, MAX_ARG_STRINGS); - if (bprm->argc < 0) - return bprm->argc; - - bprm->envc = count(envp, MAX_ARG_STRINGS); - if (bprm->envc < 0) - return bprm->envc; - /* * Limit to 1/4 of the max stack size or 3/4 of _STK_LIM * (whichever is smaller) for the argv+env strings. @@ -1964,7 +1955,17 @@ static int do_execveat_common(int fd, struct filename *filename, goto out_ret; } - retval = prepare_arg_pages(bprm, argv, envp); + retval = count(argv, MAX_ARG_STRINGS); + if (retval < 0) + goto out_free; + bprm->argc = retval; + + retval = count(envp, MAX_ARG_STRINGS); + if (retval < 0) + goto out_free; + bprm->envc = retval; + + retval = bprm_stack_limits(bprm); if (retval < 0) goto out_free; From patchwork Tue Jul 14 13:31:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Eric W. Biederman" X-Patchwork-Id: 11662883 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4AED41392 for ; Tue, 14 Jul 2020 13:34:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 33E33224D1 for ; Tue, 14 Jul 2020 13:34:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728009AbgGNNee (ORCPT ); Tue, 14 Jul 2020 09:34:34 -0400 Received: from out01.mta.xmission.com ([166.70.13.231]:49368 "EHLO out01.mta.xmission.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726624AbgGNNed (ORCPT ); Tue, 14 Jul 2020 09:34:33 -0400 Received: from in02.mta.xmission.com ([166.70.13.52]) by out01.mta.xmission.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jvL4q-0007hJ-Dn; Tue, 14 Jul 2020 07:34:32 -0600 Received: from ip68-227-160-95.om.om.cox.net ([68.227.160.95] helo=x220.xmission.com) by in02.mta.xmission.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.87) (envelope-from ) id 1jvL4n-0006tw-W9; Tue, 14 Jul 2020 07:34:32 -0600 From: ebiederm@xmission.com (Eric W. Biederman) To: Cc: Linus Torvalds , Kees Cook , Andy Lutomirski , "H. Peter Anvin" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Al Viro , Luis Chamberlain , , Tetsuo Handa , linux-security-module@vger.kernel.org, "Serge E. Hallyn" , James Morris , Kentaro Takeda , Casey Schaufler , John Johansen , Christoph Hellwig References: <871rle8bw2.fsf@x220.int.ebiederm.org> Date: Tue, 14 Jul 2020 08:31:40 -0500 In-Reply-To: <871rle8bw2.fsf@x220.int.ebiederm.org> (Eric W. Biederman's message of "Tue, 14 Jul 2020 08:27:41 -0500") Message-ID: <87wo365ikj.fsf@x220.int.ebiederm.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux) MIME-Version: 1.0 X-XM-SPF: eid=1jvL4n-0006tw-W9;;;mid=<87wo365ikj.fsf@x220.int.ebiederm.org>;;;hst=in02.mta.xmission.com;;;ip=68.227.160.95;;;frm=ebiederm@xmission.com;;;spf=neutral X-XM-AID: U2FsdGVkX1/fV97egYUdztXu6oLqZ7O0Th26wzy3roE= X-SA-Exim-Connect-IP: 68.227.160.95 X-SA-Exim-Mail-From: ebiederm@xmission.com X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on sa01.xmission.com X-Spam-Level: ** X-Spam-Status: No, score=2.9 required=8.0 tests=ALL_TRUSTED,BAYES_50, DCC_CHECK_NEGATIVE,FVGT_m_MULTI_ODD,LotsOfNums_01,T_TooManySym_01, XMNoVowels autolearn=disabled version=3.4.2 X-Spam-Virus: No X-Spam-Report: * -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP * 0.8 BAYES_50 BODY: Bayes spam probability is 40 to 60% * [score: 0.5000] * 1.5 XMNoVowels Alpha-numberic number with no vowels * 1.2 LotsOfNums_01 BODY: Lots of long strings of numbers * -0.0 DCC_CHECK_NEGATIVE Not listed in DCC * [sa01 0; Body=1 Fuz1=1 Fuz2=1] * 0.0 T_TooManySym_01 4+ unique symbols in subject * 0.4 FVGT_m_MULTI_ODD Contains multiple odd letter combinations X-Spam-DCC: ; sa01 0; Body=1 Fuz1=1 Fuz2=1 X-Spam-Combo: **; X-Spam-Relay-Country: X-Spam-Timing: total 2006 ms - load_scoreonly_sql: 0.04 (0.0%), signal_user_changed: 4.6 (0.2%), b_tie_ro: 3.2 (0.2%), parse: 1.62 (0.1%), extract_message_metadata: 14 (0.7%), get_uri_detail_list: 4.6 (0.2%), tests_pri_-1000: 2.9 (0.1%), tests_pri_-950: 1.06 (0.1%), tests_pri_-900: 0.88 (0.0%), tests_pri_-90: 169 (8.4%), check_bayes: 155 (7.7%), b_tokenize: 30 (1.5%), b_tok_get_all: 17 (0.9%), b_comp_prob: 4.2 (0.2%), b_tok_touch_all: 99 (4.9%), b_finish: 0.76 (0.0%), tests_pri_0: 1798 (89.6%), check_dkim_signature: 0.81 (0.0%), check_dkim_adsp: 2.6 (0.1%), poll_dns_idle: 0.78 (0.0%), tests_pri_10: 2.7 (0.1%), tests_pri_500: 8 (0.4%), rewrite_mail: 0.00 (0.0%) Subject: [PATCH 7/7] exec: Implement kernel_execve X-Spam-Flag: No X-SA-Exim-Version: 4.2.1 (built Thu, 05 May 2016 13:38:54 -0600) X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org To allow the kernel not to play games with set_fs to call exec implement kernel_execve. The function kernel_execve takes pointers into kernel memory and copies the values pointed to onto the new userspace stack. The calls with arguments from kernel space of do_execve are replaced with calls to kernel_execve. The calls do_execve and do_execveat are made static as there are now no callers outside of exec. The comments that mention do_execve are updated to refer to kernel_execve or execve depending on the circumstances. In addition to correcting the comments, this makes it easy to grep for do_execve and verify it is not used. Inspired-by: https://lkml.kernel.org/r/20200627072704.2447163-1-hch@lst.de Signed-off-by: "Eric W. Biederman" Reviewed-by: Kees Cook --- arch/x86/entry/entry_32.S | 2 +- arch/x86/entry/entry_64.S | 2 +- arch/x86/kernel/unwind_frame.c | 2 +- fs/exec.c | 88 +++++++++++++++++++++++++++++++++- include/linux/binfmts.h | 9 +--- init/main.c | 4 +- kernel/umh.c | 6 +-- security/tomoyo/common.h | 2 +- security/tomoyo/domain.c | 4 +- security/tomoyo/tomoyo.c | 4 +- 10 files changed, 100 insertions(+), 23 deletions(-) diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S index 024d7d276cd4..8f4e085ee06d 100644 --- a/arch/x86/entry/entry_32.S +++ b/arch/x86/entry/entry_32.S @@ -854,7 +854,7 @@ SYM_CODE_START(ret_from_fork) CALL_NOSPEC ebx /* * A kernel thread is allowed to return here after successfully - * calling do_execve(). Exit to userspace to complete the execve() + * calling kernel_execve(). Exit to userspace to complete the execve() * syscall. */ movl $0, PT_EAX(%esp) diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index d2a00c97e53f..73c7e255256b 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -293,7 +293,7 @@ SYM_CODE_START(ret_from_fork) CALL_NOSPEC rbx /* * A kernel thread is allowed to return here after successfully - * calling do_execve(). Exit to userspace to complete the execve() + * calling kernel_execve(). Exit to userspace to complete the execve() * syscall. */ movq $0, RAX(%rsp) diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c index 722a85f3b2dd..e40b4942157f 100644 --- a/arch/x86/kernel/unwind_frame.c +++ b/arch/x86/kernel/unwind_frame.c @@ -275,7 +275,7 @@ bool unwind_next_frame(struct unwind_state *state) * This user_mode() check is slightly broader than a PF_KTHREAD * check because it also catches the awkward situation where a * newly forked kthread transitions into a user task by calling - * do_execve(), which eventually clears PF_KTHREAD. + * kernel_execve(), which eventually clears PF_KTHREAD. */ if (!user_mode(regs)) goto the_end; diff --git a/fs/exec.c b/fs/exec.c index f8135dc149b3..3698252719a3 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -448,6 +448,23 @@ static int count(struct user_arg_ptr argv, int max) return i; } +static int count_strings_kernel(const char *const *argv) +{ + int i; + + if (!argv) + return 0; + + for (i = 0; argv[i]; ++i) { + if (i >= MAX_ARG_STRINGS) + return -E2BIG; + if (fatal_signal_pending(current)) + return -ERESTARTNOHAND; + cond_resched(); + } + return i; +} + static int bprm_stack_limits(struct linux_binprm *bprm) { unsigned long limit, ptr_size; @@ -624,6 +641,20 @@ 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) +{ + while (argc-- > 0) { + int ret = copy_string_kernel(argv[argc], bprm); + if (ret < 0) + return ret; + if (fatal_signal_pending(current)) + return -ERESTARTNOHAND; + cond_resched(); + } + return 0; +} + #ifdef CONFIG_MMU /* @@ -1991,7 +2022,60 @@ static int do_execveat_common(int fd, struct filename *filename, return retval; } -int do_execve(struct filename *filename, +int kernel_execve(const char *kernel_filename, + const char *const *argv, const char *const *envp) +{ + struct filename *filename; + struct linux_binprm *bprm; + int fd = AT_FDCWD; + int retval; + + filename = getname_kernel(kernel_filename); + if (IS_ERR(filename)) + return PTR_ERR(filename); + + bprm = alloc_bprm(fd, filename); + if (IS_ERR(bprm)) { + retval = PTR_ERR(bprm); + goto out_ret; + } + + retval = count_strings_kernel(argv); + if (retval < 0) + goto out_free; + bprm->argc = retval; + + retval = count_strings_kernel(envp); + if (retval < 0) + goto out_free; + bprm->envc = retval; + + retval = bprm_stack_limits(bprm); + if (retval < 0) + goto out_free; + + retval = copy_string_kernel(bprm->filename, bprm); + if (retval < 0) + goto out_free; + bprm->exec = bprm->p; + + retval = copy_strings_kernel(bprm->envc, envp, bprm); + if (retval < 0) + goto out_free; + + retval = copy_strings_kernel(bprm->argc, argv, bprm); + if (retval < 0) + goto out_free; + + retval = bprm_execve(bprm, fd, filename, 0); +out_free: + free_bprm(bprm); +out_ret: + putname(filename); + return retval; +} + +static int do_execve(struct filename *filename, const char __user *const __user *__argv, const char __user *const __user *__envp) { @@ -2000,7 +2084,7 @@ int do_execve(struct filename *filename, return do_execveat_common(AT_FDCWD, filename, argv, envp, 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, int flags) diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 8e9e1b0c8eb8..0571701ab1c5 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -135,12 +135,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); -extern int do_execve(struct filename *, - const char __user * const __user *, - const char __user * const __user *); -extern int do_execveat(int, struct filename *, - const char __user * const __user *, - const char __user * const __user *, - int); +int kernel_execve(const char *filename, + const char *const *argv, const char *const *envp); #endif /* _LINUX_BINFMTS_H */ diff --git a/init/main.c b/init/main.c index 0ead83e86b5a..78ccec5c28f3 100644 --- a/init/main.c +++ b/init/main.c @@ -1329,9 +1329,7 @@ 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_execve(getname_kernel(init_filename), - (const char __user *const __user *)argv_init, - (const char __user *const __user *)envp_init); + return kernel_execve(init_filename, argv_init, envp_init); } static int try_to_run_init_process(const char *init_filename) diff --git a/kernel/umh.c b/kernel/umh.c index 6ca2096298b9..a25433f9cd9a 100644 --- a/kernel/umh.c +++ b/kernel/umh.c @@ -98,9 +98,9 @@ static int call_usermodehelper_exec_async(void *data) commit_creds(new); - retval = do_execve(getname_kernel(sub_info->path), - (const char __user *const __user *)sub_info->argv, - (const char __user *const __user *)sub_info->envp); + retval = kernel_execve(sub_info->path, + (const char *const *)sub_info->argv, + (const char *const *)sub_info->envp); out: sub_info->retval = retval; /* diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 050473df5809..85246b9df7ca 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -425,7 +425,7 @@ struct tomoyo_request_info { struct tomoyo_obj_info *obj; /* * For holding parameters specific to execve() request. - * NULL if not dealing do_execve(). + * NULL if not dealing execve(). */ struct tomoyo_execve *ee; struct tomoyo_domain_info *domain; diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 7869d6a9980b..53b3e1f5f227 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -767,7 +767,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) /* * Check for domain transition preference if "file execute" matched. - * If preference is given, make do_execve() fail if domain transition + * If preference is given, make execve() fail if domain transition * has failed, for domain transition preference should be used with * destination domain defined. */ @@ -810,7 +810,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", candidate->name); /* - * Make do_execve() fail if domain transition across namespaces + * Make execve() fail if domain transition across namespaces * has failed. */ reject_on_transition_failure = true; diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index f9adddc42ac8..1f3cd432d830 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -93,7 +93,7 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) struct tomoyo_task *s = tomoyo_task(current); /* - * Execute permission is checked against pathname passed to do_execve() + * Execute permission is checked against pathname passed to execve() * using current domain. */ if (!s->old_domain_info) { @@ -307,7 +307,7 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, */ static int tomoyo_file_open(struct file *f) { - /* Don't check read permission here if called from do_execve(). */ + /* Don't check read permission here if called from execve(). */ if (current->in_execve) return 0; return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path,