From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752568AbdGFEck (ORCPT ); Thu, 6 Jul 2017 00:32:40 -0400 Received: from mail-pf0-f179.google.com ([209.85.192.179]:36832 "EHLO mail-pf0-f179.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750968AbdGFEci (ORCPT ); Thu, 6 Jul 2017 00:32:38 -0400 Date: Wed, 5 Jul 2017 21:32:35 -0700 From: Kees Cook To: Linus Torvalds , Andy Lutomirski Cc: Michal Hocko , Ben Hutchings , Willy Tarreau , Hugh Dickins , Oleg Nesterov , "Jason A. Donenfeld" , Rik van Riel , Larry Woodman , "Kirill A. Shutemov" , Tony Luck , "James E.J. Bottomley" , Helge Diller , James Hogan , Laura Abbott , Greg KH , "security@kernel.org" , Qualys Security Advisory , LKML , Ximin Luo Subject: [RFC][PATCH] exec: Use init rlimits for setuid exec Message-ID: <20170706043235.GA36170@beast> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In an attempt to provide sensible rlimit defaults for setuid execs, this inherits the namespace's init rlimits: $ ulimit -s 8192 $ ulimit -s unlimited $ /bin/sh -c 'ulimit -s' unlimited $ sudo /bin/sh -c 'ulimit -s' 8192 This is modified from Brad Spengler/PaX Team's hard-coded setuid exec stack rlimit (8MB) in the last public patch of grsecurity/PaX based on my understanding of the code. Changes or omissions from the original code are mine and don't reflect the original grsecurity/PaX code. Signed-off-by: Kees Cook --- Instead of copying all rlimits, we could also pick specific ones to copy (e.g. RLIMIT_STACK, or ones from Andy's list) or exclude from copying (probably better to blacklist than whitelist). I think this is the right way to find the ns init task, but maybe it needs locking? --- fs/exec.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 904199086490..80e8b2bd4284 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1675,6 +1675,12 @@ static int exec_binprm(struct linux_binprm *bprm) return ret; } +static inline bool is_setuid_exec(struct linux_binprm *bprm) +{ + return (!uid_eq(bprm->cred->euid, current_euid()) || + !gid_eq(bprm->cred->egid, current_egid())); +} + /* * sys_execve() executes a new program. */ @@ -1687,6 +1693,7 @@ static int do_execveat_common(int fd, struct filename *filename, struct linux_binprm *bprm; struct file *file; struct files_struct *displaced; + struct rlimit saved_rlim[RLIM_NLIMITS]; int retval; if (IS_ERR(filename)) @@ -1771,24 +1778,38 @@ static int do_execveat_common(int fd, struct filename *filename, if (retval < 0) goto out; + /* + * From here forward, we've got credentials set up and we're + * using resources, so do rlimit replacement before we start + * copying strings. (Note that the RLIMIT_NPROC check has + * already happened.) + */ + BUILD_BUG_ON(sizeof(saved_rlim) != sizeof(current->signal->rlim)); + if (is_setuid_exec(bprm)) { + memcpy(saved_rlim, current->signal->rlim, sizeof(saved_rlim)); + memcpy(current->signal->rlim, + task_active_pid_ns(current)->child_reaper->signal->rlim, + sizeof(current->signal->rlim)); + } + retval = copy_strings_kernel(1, &bprm->filename, bprm); if (retval < 0) - goto out; + goto out_restore; bprm->exec = bprm->p; retval = copy_strings(bprm->envc, envp, bprm); if (retval < 0) - goto out; + goto out_restore; retval = copy_strings(bprm->argc, argv, bprm); if (retval < 0) - goto out; + goto out_restore; would_dump(bprm, bprm->file); retval = exec_binprm(bprm); if (retval < 0) - goto out; + goto out_restore; /* execve succeeded */ current->fs->in_exec = 0; @@ -1802,6 +1823,11 @@ static int do_execveat_common(int fd, struct filename *filename, put_files_struct(displaced); return retval; +out_restore: + if (is_setuid_exec(bprm)) { + memcpy(current->signal->rlim, saved_rlim, sizeof(saved_rlim)); + } + out: if (bprm->mm) { acct_arg_size(bprm, 0); -- 2.7.4 -- Kees Cook Pixel Security