From patchwork Sat Feb 25 12:56:13 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konstantin Khlebnikov X-Patchwork-Id: 9591701 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 02AAF6042C for ; Sat, 25 Feb 2017 13:03:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DB63A285D1 for ; Sat, 25 Feb 2017 13:03:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CF5DC28636; Sat, 25 Feb 2017 13:03:44 +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=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, 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 5B9FB285D1 for ; Sat, 25 Feb 2017 13:03:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751319AbdBYNDn (ORCPT ); Sat, 25 Feb 2017 08:03:43 -0500 Received: from forwardcorp1o.cmail.yandex.net ([37.9.109.47]:48852 "EHLO forwardcorp1o.cmail.yandex.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751214AbdBYNDm (ORCPT ); Sat, 25 Feb 2017 08:03:42 -0500 X-Greylist: delayed 441 seconds by postgrey-1.27 at vger.kernel.org; Sat, 25 Feb 2017 08:03:42 EST Received: from smtpcorp1p.mail.yandex.net (smtpcorp1p.mail.yandex.net [IPv6:2a02:6b8:0:1472:2741:0:8b6:10]) by forwardcorp1o.cmail.yandex.net (Yandex) with ESMTP id 40AD720C66; Sat, 25 Feb 2017 15:56:17 +0300 (MSK) Received: from smtpcorp1p.mail.yandex.net (localhost.localdomain [127.0.0.1]) by smtpcorp1p.mail.yandex.net (Yandex) with ESMTP id 324036E40C09; Sat, 25 Feb 2017 15:56:17 +0300 (MSK) Received: from unknown (unknown [2a02:6b8:0:5::1:39]) by smtpcorp1p.mail.yandex.net (nwsmtp/Yandex) with ESMTPSA id fK2LLgTe85-uH1Wjkmm; Sat, 25 Feb 2017 15:56:17 +0300 (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client certificate not present) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex-team.ru; s=default; t=1488027377; bh=nOpge93N5lTSnisIWymabt/5BAVRmJ7oGqiVqVZkDwE=; h=Subject:From:To:Cc:Date:Message-ID; b=Tn+wnG+n/iJ6pqQuKnc2rE/W0GDKj6zT/Mn7UakMqxgCmzvg5NF85xbVwpRXkvakk bKeiW5IgvcsBGPEAtYTCpEz//lOSre+3K0Vb6JmINtD3hpgn//WXe2agFdsEvNvTIV UvGBXQGSM54/waaRxWr+YNmnMly1jWSlVpGsLU3U= Authentication-Results: smtpcorp1p.mail.yandex.net; dkim=pass header.i=@yandex-team.ru Subject: [PATCH RFC] coredump: virtualize core dump path configuration From: Konstantin Khlebnikov To: containers@lists.linux-foundation.org, linux-kernel@vger.kernel.org Cc: Andrey Vagin , Oleg Nesterov , Alexander Viro , "Eric W. Biederman" , linux-fsdevel@vger.kernel.org, Serge Hallyn Date: Sat, 25 Feb 2017 15:56:13 +0300 Message-ID: <148802737321.604836.9948660933476794784.stgit@buzz> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 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 This patch adds per-mount-namespace core dump pattern. Kernel writes coredump in chroot/container where application is executed or starts pipe helper in the same chroot according to pattern set by sysctl "kernel.core_pattern". This configuration is global and this sysctl couldn't be extended without breaking anything. This patch adds second sysctl "kernel.core_pattern_ns" which overrides global configuration for tasks in current mount namespace. Resetting it to empty string reverts core dumps back to global pattern. New namespace gets a copy of this configuration from parent. Signed-off-by: Konstantin Khlebnikov --- Documentation/sysctl/kernel.txt | 9 +++++++++ fs/coredump.c | 27 ++++++++++++++++++++++++++- fs/mount.h | 1 + fs/namespace.c | 12 ++++++++++++ kernel/sysctl.c | 26 +++++++++++++++++++++++++- 5 files changed, 73 insertions(+), 2 deletions(-) diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index a32b4b748644..769aa00df898 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -26,6 +26,7 @@ show up in /proc/sys/kernel: - callhome [ S390 only ] - cap_last_cap - core_pattern +- core_pattern_ns - core_pipe_limit - core_uses_pid - ctrl-alt-del @@ -219,6 +220,14 @@ core_pattern is used to specify a core dumpfile pattern name. ============================================================== +core_pattern_ns: + +This sysctl has the same format as core_pattern. Any non-empty string +set here overrides core_pattern for tasks in current mount namespace. +New mount namespace gets a copy of this configuration from parent. + +============================================================== + core_pipe_limit: This sysctl is only applicable when core_pattern is configured to pipe diff --git a/fs/coredump.c b/fs/coredump.c index ae6b05629ca1..9c789496d4c6 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -45,6 +45,7 @@ #include #include "internal.h" +#include "mount.h" #include @@ -180,6 +181,30 @@ static int cn_print_exe_file(struct core_name *cn) return ret; } +char *namespace_core_pattern(bool alloc) +{ + struct mnt_namespace *ns = current->nsproxy->mnt_ns; + + if (!ns->core_pattern && alloc) { + char *new = kzalloc(CORENAME_MAX_SIZE, GFP_KERNEL); + + if (new && cmpxchg(&ns->core_pattern, NULL, new)) + kfree(new); + } + + return ns->core_pattern; +} + +static char *current_core_pattern(void) +{ + struct mnt_namespace *ns = current->nsproxy->mnt_ns; + + if (ns->core_pattern && ns->core_pattern[0]) + return ns->core_pattern; + + return core_pattern; +} + /* format_corename will inspect the pattern parameter, and output a * name into corename, which must have space for at least * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator. @@ -187,7 +212,7 @@ static int cn_print_exe_file(struct core_name *cn) static int format_corename(struct core_name *cn, struct coredump_params *cprm) { const struct cred *cred = current_cred(); - const char *pat_ptr = core_pattern; + const char *pat_ptr = current_core_pattern(); int ispipe = (*pat_ptr == '|'); int pid_in_pattern = 0; int err = 0; diff --git a/fs/mount.h b/fs/mount.h index 2c856fc47ae3..894bca887104 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -16,6 +16,7 @@ struct mnt_namespace { u64 event; unsigned int mounts; /* # of mounts in the namespace */ unsigned int pending_mounts; + char *core_pattern; }; struct mnt_pcp { diff --git a/fs/namespace.c b/fs/namespace.c index 487ba30bb5c6..a8dd58eb10da 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -24,6 +24,7 @@ #include #include #include +#include /* CORENAME_MAX_SIZE */ #include "pnode.h" #include "internal.h" @@ -2828,6 +2829,7 @@ static void free_mnt_ns(struct mnt_namespace *ns) ns_free_inum(&ns->ns); dec_mnt_namespaces(ns->ucounts); put_user_ns(ns->user_ns); + kfree(ns->core_pattern); kfree(ns); } @@ -2872,6 +2874,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) new_ns->ucounts = ucounts; new_ns->mounts = 0; new_ns->pending_mounts = 0; + new_ns->core_pattern = NULL; return new_ns; } @@ -2899,6 +2902,15 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, if (IS_ERR(new_ns)) return new_ns; + if (ns->core_pattern) { + new_ns->core_pattern = kmemdup(ns->core_pattern, + CORENAME_MAX_SIZE, GFP_KERNEL); + if (!new_ns->core_pattern) { + free_mnt_ns(new_ns); + return ERR_PTR(-ENOMEM); + } + } + namespace_lock(); /* First pass: copy the tree topology */ copy_flags = CL_COPY_UNBINDABLE | CL_EXPIRE; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 1aea594a54db..9e66daf1e236 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -483,6 +483,13 @@ static struct ctl_table kern_table[] = { .proc_handler = proc_dostring_coredump, }, { + .procname = "core_pattern_ns", + .data = NULL, + .maxlen = CORENAME_MAX_SIZE, + .mode = 0644, + .proc_handler = proc_dostring_coredump, + }, + { .procname = "core_pipe_limit", .data = &core_pipe_limit, .maxlen = sizeof(unsigned int), @@ -2408,10 +2415,27 @@ static int proc_dointvec_minmax_coredump(struct ctl_table *table, int write, } #ifdef CONFIG_COREDUMP +extern char *namespace_core_pattern(bool alloc); + static int proc_dostring_coredump(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - int error = proc_dostring(table, write, buffer, lenp, ppos); + struct ctl_table tmp_table; + char empty[] = ""; + int error; + + if (!table->data) { + tmp_table = *table; + table = &tmp_table; + table->data = namespace_core_pattern(write); + if (!table->data) { + if (write) + return -ENOMEM; + table->data = empty; + } + } + + error = proc_dostring(table, write, buffer, lenp, ppos); if (!error) validate_coredump_safety(); return error;