From patchwork Tue Jan 9 20:23:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 10153247 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 CCDD760223 for ; Tue, 9 Jan 2018 20:24:13 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CA0CE23B34 for ; Tue, 9 Jan 2018 20:24:13 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BD3E623E64; Tue, 9 Jan 2018 20:24:13 +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=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id 87A47237F1 for ; Tue, 9 Jan 2018 20:24:12 +0000 (UTC) Received: (qmail 20390 invoked by uid 550); 9 Jan 2018 20:23:36 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 20231 invoked from network); 9 Jan 2018 20:23:33 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=LA7EJPmUwG9z/MnqwEBDBqi6ej4N+VzeN4FDY1vnsBY=; b=BmTvSfJmlI4d2zJXCdK/te/Hdk5k3cPu+rGvsl6Qlqnybalg4AW47ieL/97uHTq9x9 oFQQcagfPzHy7oiePtvZEctziGpvI9gN+/KcWQR6TUFgOlzrhplLt+uhwL5ZvyrFSinu i1kdqRPCudKXsHgDKgm2Sor04d/1g9ud+ISmM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=LA7EJPmUwG9z/MnqwEBDBqi6ej4N+VzeN4FDY1vnsBY=; b=m4NStXAWtXLe6z8uzsfXtYbxNwp2mz2+OoKeACz5fo9CbAHrtKv+hG1/n1fkCOrWSw C5MqClXhBKysuOMHvo6RECJ9zlFX5WL+1xPKMOIfepttbtHaM1Dxi+o2F9Mp1WtTV8H0 bLKMKEzIiJkKj0yXIPXkRnhvrRDxwqasgRZnM5LTsGk1O2eUhSGYMNz1s69V/aQluXK3 0DNK5xQjrdVaf+zVcSJ1cMOmUc5J8zeFUYaw+9ycMABairdsB4oma0oi+5N6yixYfc0v DLGALnbVJWcfxNDvXr+jBMVXYdev3u4mS7taChbODbAATX30KnjmO7HufxGJ33BjnBiV j+mg== X-Gm-Message-State: AKGB3mKDYvNSRU3snQJgdAK+W4F2pzYlt48H8KeFSk/PyPPFb7NlpFcy 2kkWD0foBv+wOEM3jtGed6VrtQ== X-Google-Smtp-Source: ACJfBotKv6Zs9CdZXmbwXcm/G2R1iCN1+iHjxWxxT20Q4r9f9VHbc70XwnL3g5lTTo97E26AeWP59A== X-Received: by 10.101.76.75 with SMTP id l11mr13137083pgr.187.1515529401285; Tue, 09 Jan 2018 12:23:21 -0800 (PST) From: Kees Cook To: Andrew Morton Cc: Kees Cook , Linus Torvalds , Michal Hocko , Ben Hutchings , Willy Tarreau , Hugh Dickins , Oleg Nesterov , "Jason A. Donenfeld" , Rik van Riel , Laura Abbott , Greg KH , Andy Lutomirski , linux-mm@kvack.org, linux-arch@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-hardening@lists.openwall.com Date: Tue, 9 Jan 2018 12:23:03 -0800 Message-Id: <1515529383-35695-4-git-send-email-keescook@chromium.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1515529383-35695-1-git-send-email-keescook@chromium.org> References: <1515529383-35695-1-git-send-email-keescook@chromium.org> Subject: [kernel-hardening] [PATCH 3/3] exec: Pin stack limit during exec X-Virus-Scanned: ClamAV using ClamSMTP Since the stack rlimit is used in multiple places during exec and it can be changed via other threads (via setrlimit()) or processes (via prlimit()), the assumption that the value doesn't change cannot be made. This leads to races with mm layout selection and argument size calculations. This changes the exec path to use the rlimit stored in bprm instead of in current. Before starting the thread, the bprm stack rlimit is stored back to current. Reported-by: Ben Hutchings Reported-by: Andy Lutomirski Reported-by: Brad Spengler Fixes: 64701dee4178e ("exec: Use sane stack rlimit under secureexec") Signed-off-by: Kees Cook --- fs/exec.c | 27 +++++++++++++++------------ include/linux/binfmts.h | 2 ++ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index e4ae20ff6278..806936ad9387 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -257,7 +257,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, * to work from. */ limit = _STK_LIM / 4 * 3; - limit = min(limit, rlimit(RLIMIT_STACK) / 4); + limit = min(limit, bprm->rlim_stack.rlim_cur / 4); if (size > limit) goto fail; } @@ -411,6 +411,11 @@ static int bprm_mm_init(struct linux_binprm *bprm) if (!mm) goto err; + /* Save current stack limit for all calculations made during exec. */ + task_lock(current->group_leader); + bprm->rlim_stack = current->signal->rlim[RLIMIT_STACK]; + task_unlock(current->group_leader); + err = __bprm_mm_init(bprm); if (err) goto err; @@ -697,7 +702,7 @@ int setup_arg_pages(struct linux_binprm *bprm, #ifdef CONFIG_STACK_GROWSUP /* Limit stack size */ - stack_base = rlimit_max(RLIMIT_STACK); + stack_base = bprm->rlim_stack.rlim_max; if (stack_base > STACK_SIZE_MAX) stack_base = STACK_SIZE_MAX; @@ -770,7 +775,7 @@ int setup_arg_pages(struct linux_binprm *bprm, * Align this down to a page boundary as expand_stack * will align it up. */ - rlim_stack = rlimit(RLIMIT_STACK) & PAGE_MASK; + rlim_stack = bprm->rlim_stack.rlim_cur & PAGE_MASK; #ifdef CONFIG_STACK_GROWSUP if (stack_size + stack_expand > rlim_stack) stack_base = vma->vm_start + rlim_stack; @@ -1323,8 +1328,6 @@ EXPORT_SYMBOL(would_dump); void setup_new_exec(struct linux_binprm * bprm) { - struct rlimit rlim_stack; - /* * Once here, prepare_binrpm() will not be called any more, so * the final state of setuid/setgid/fscaps can be merged into the @@ -1343,15 +1346,11 @@ void setup_new_exec(struct linux_binprm * bprm) * RLIMIT_STACK, but after the point of no return to avoid * needing to clean up the change on failure. */ - if (current->signal->rlim[RLIMIT_STACK].rlim_cur > _STK_LIM) - current->signal->rlim[RLIMIT_STACK].rlim_cur = _STK_LIM; + if (bprm->rlim_stack.rlim_cur > _STK_LIM) + bprm->rlim_stack.rlim_cur = _STK_LIM; } - task_lock(current->group_leader); - rlim_stack = current->signal->rlim[RLIMIT_STACK]; - task_unlock(current->group_leader); - - arch_pick_mmap_layout(current->mm, &rlim_stack); + arch_pick_mmap_layout(current->mm, &bprm->rlim_stack); current->sas_ss_sp = current->sas_ss_size = 0; @@ -1387,6 +1386,10 @@ EXPORT_SYMBOL(setup_new_exec); /* Runs immediately before start_thread() takes over. */ void finalize_exec(struct linux_binprm *bprm) { + /* Store any stack rlimit changes before starting thread. */ + task_lock(current->group_leader); + current->signal->rlim[RLIMIT_STACK] = bprm->rlim_stack; + task_unlock(current->group_leader); } EXPORT_SYMBOL(finalize_exec); diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 40e52afbb2b0..4955e0863b83 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -61,6 +61,8 @@ struct linux_binprm { unsigned interp_flags; unsigned interp_data; unsigned long loader, exec; + + struct rlimit rlim_stack; /* Saved RLIMIT_STACK used during exec. */ } __randomize_layout; #define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0