From patchwork Wed Aug 31 21:12:49 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrey Vagin X-Patchwork-Id: 9307887 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 39E7B601C0 for ; Wed, 31 Aug 2016 21:13:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2571228F9F for ; Wed, 31 Aug 2016 21:13:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 19208290D1; Wed, 31 Aug 2016 21:13:09 +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.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, T_TVD_MIME_EPI autolearn=ham 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 0A93328F9F for ; Wed, 31 Aug 2016 21:13:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754059AbcHaVMx (ORCPT ); Wed, 31 Aug 2016 17:12:53 -0400 Received: from mail-it0-f67.google.com ([209.85.214.67]:36521 "EHLO mail-it0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753824AbcHaVMv (ORCPT ); Wed, 31 Aug 2016 17:12:51 -0400 Received: by mail-it0-f67.google.com with SMTP id i184so3816316itf.3; Wed, 31 Aug 2016 14:12:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to:cc; bh=vyaOJdwbLFWkx6oQZ8zIf4nsA8nBXdo8YqDm86WhOhU=; b=tgd7GF6P84+uRHPjzjHzxrncGCHfsZ8On3M6a2vL80X58b+X/0QryCjxXhul6e0KZS P4ESogGeYCwnyTfsIGCJxGoaz/1Y950e7X1XcalcSpJo/xX2+HsKAxh/1Fy3d5bOU/FV rxxbNKVCnf6NGZCepts+QvN3R1V6Fge3QmnxKVsH8HtW4SqrKuyh9MokE9K03tovK9+3 gSq/PhfwuNqjZRxyl8HT5ZKafCOgzqySlDrEuf6m77DdaJNdkKSBoqw5b4Rb8PHq8ojh SwhzHDk3NswfhLI+hRe3q6Fb8Ni9p7y543LVIqDBOKz3cv/b8ni7923sDMhfBMV84Jft CZgg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:sender:in-reply-to:references:from :date:message-id:subject:to:cc; bh=vyaOJdwbLFWkx6oQZ8zIf4nsA8nBXdo8YqDm86WhOhU=; b=F6/sQ7PYwvoiWN+RzNpJCvHiiHiIydQj+rZBr3S0fpdwWJy9UhGb+AipufHWvN7O4h s4DnvlrRLemGoXB3VXfYQxcpA6QfW2F3XGd11Gw8D4f5SWlaHt9HomwGmBJbb7eUiAEf LSKLquZnMDNNOxDqkJ6WBzA6itdvSCUknXUk9f8AO30STIR76Lb/C0BkwthKlMwYlbmV knJ43YYNLYxOyb19MzPJEAOlpoHtfJUxPnLQTkG8PDnsCq0S2Tu3jXPpsDh/jvTIrGIb 598F9pJuGtmt5xB1EP2VoKz7zqC8V37Sa1oFv5S9fsXe3Nwx+ccsDogleBPPVyDyFdzG k1Dg== X-Gm-Message-State: AE9vXwMlCWPjEdnkncD8jeWQfFRnmqj4Ztlpkc+0PHPVDd6COas4ppUfXDLGrGXZ0tNuMGUw4GSTLmtxCtCbsQ== X-Received: by 10.36.129.213 with SMTP id q204mr36028464itd.38.1472677970350; Wed, 31 Aug 2016 14:12:50 -0700 (PDT) MIME-Version: 1.0 Received: by 10.36.36.85 with HTTP; Wed, 31 Aug 2016 14:12:49 -0700 (PDT) In-Reply-To: <20160831024146.GB21475@mail.hallyn.com> References: <1472252891-4963-1-git-send-email-avagin@openvz.org> <1472252891-4963-2-git-send-email-avagin@openvz.org> <20160831024146.GB21475@mail.hallyn.com> From: Andrey Vagin Date: Wed, 31 Aug 2016 14:12:49 -0700 X-Google-Sender-Auth: jWJSlZztmWgzzJLkWLgMyxfuCH8 Message-ID: Subject: Re: [PATCH 1/4] kernel: add a helper to get an owning user namespace for a namespace To: "Serge E. Hallyn" Cc: "Eric W. Biederman" , Linux Containers , Linux API , LKML , James Bottomley , "Michael Kerrisk (man-pages)" , linux-fsdevel , Alexander Viro 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 On Tue, Aug 30, 2016 at 7:41 PM, Serge E. Hallyn wrote: > On Fri, Aug 26, 2016 at 04:08:08PM -0700, Andrei Vagin wrote: >> From: Andrey Vagin >> >> Return -EPERM if an owning user namespace is outside of a process >> current user namespace. >> >> v2: In a first version ns_get_owner returned ENOENT for init_user_ns. >> This special cases was removed from this version. There is nothing >> outside of init_user_ns, so we can return EPERM. >> >> Signed-off-by: Andrei Vagin >> --- >> fs/namespace.c | 6 ++++++ >> include/linux/proc_ns.h | 1 + >> include/linux/user_namespace.h | 7 +++++++ >> ipc/namespace.c | 6 ++++++ >> kernel/cgroup.c | 6 ++++++ >> kernel/pid_namespace.c | 6 ++++++ >> kernel/user_namespace.c | 24 ++++++++++++++++++++++++ >> kernel/utsname.c | 6 ++++++ >> net/core/net_namespace.c | 6 ++++++ >> 9 files changed, 68 insertions(+) >> >> diff --git a/fs/namespace.c b/fs/namespace.c >> index 491b8f3..f985817 100644 >> --- a/fs/namespace.c >> +++ b/fs/namespace.c >> @@ -3368,10 +3368,16 @@ static int mntns_install(struct nsproxy *nsproxy, struct ns_common *ns) >> return 0; >> } >> >> +static struct user_namespace *mntns_get_owner(struct ns_common *ns) >> +{ >> + return to_mnt_ns(ns)->user_ns; > > Hi - sorry to be pedantic here, but *_get_owner makes me think > it will grab a reference too. A bit unfortunate, maybe it doesn't > matter, but would mntns_owner(), netns_owner(), etc be better? Actually it looks reasonable. Especially, when we have get_parent() which grabs a reference. Serge, could you look at the attached patch? I will need to rebase other patches, if we accept this patch. Thanks, Andrei Acked-by: Serge Hallyn From 423b2226dc9bcfefccbec21663e9287addd67e0f Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Tue, 12 Jul 2016 15:32:36 -0700 Subject: [PATCH] kernel: add a helper to get an owning user namespace for a namespace Return -EPERM if an owning user namespace is outside of a process current user namespace. v2: In a first version ns_get_owner returned ENOENT for init_user_ns. This special cases was removed from this version. There is nothing outside of init_user_ns, so we can return EPERM. v3: rename ns->get_owner() to ns->owner(). get_* usually means that it grabs a reference. Signed-off-by: Andrei Vagin --- fs/namespace.c | 6 ++++++ include/linux/proc_ns.h | 1 + include/linux/user_namespace.h | 7 +++++++ ipc/namespace.c | 6 ++++++ kernel/cgroup.c | 6 ++++++ kernel/pid_namespace.c | 6 ++++++ kernel/user_namespace.c | 24 ++++++++++++++++++++++++ kernel/utsname.c | 6 ++++++ net/core/net_namespace.c | 6 ++++++ 9 files changed, 68 insertions(+) diff --git a/fs/namespace.c b/fs/namespace.c index 491b8f3..dd27ce4 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -3368,10 +3368,16 @@ static int mntns_install(struct nsproxy *nsproxy, struct ns_common *ns) return 0; } +static struct user_namespace *mntns_owner(struct ns_common *ns) +{ + return to_mnt_ns(ns)->user_ns; +} + const struct proc_ns_operations mntns_operations = { .name = "mnt", .type = CLONE_NEWNS, .get = mntns_get, .put = mntns_put, .install = mntns_install, + .owner = mntns_owner, }; diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h index de0e771..ca85a43 100644 --- a/include/linux/proc_ns.h +++ b/include/linux/proc_ns.h @@ -18,6 +18,7 @@ struct proc_ns_operations { struct ns_common *(*get)(struct task_struct *task); void (*put)(struct ns_common *ns); int (*install)(struct nsproxy *nsproxy, struct ns_common *ns); + struct user_namespace *(*owner)(struct ns_common *ns); }; extern const struct proc_ns_operations netns_operations; diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 30ffe10..eb209d4 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -106,6 +106,8 @@ extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t, extern int proc_setgroups_show(struct seq_file *m, void *v); extern bool userns_may_setgroups(const struct user_namespace *ns); extern bool current_in_userns(const struct user_namespace *target_ns); + +struct ns_common *ns_get_owner(struct ns_common *ns); #else static inline struct user_namespace *get_user_ns(struct user_namespace *ns) @@ -139,6 +141,11 @@ static inline bool current_in_userns(const struct user_namespace *target_ns) { return true; } + +static inline struct ns_common *ns_get_owner(struct ns_common *ns) +{ + return ERR_PTR(-EPERM); +} #endif #endif /* _LINUX_USER_H */ diff --git a/ipc/namespace.c b/ipc/namespace.c index 7309142..465c981 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c @@ -188,10 +188,16 @@ static int ipcns_install(struct nsproxy *nsproxy, struct ns_common *new) return 0; } +static struct user_namespace *ipcns_owner(struct ns_common *ns) +{ + return to_ipc_ns(ns)->user_ns; +} + const struct proc_ns_operations ipcns_operations = { .name = "ipc", .type = CLONE_NEWIPC, .get = ipcns_get, .put = ipcns_put, .install = ipcns_install, + .owner = ipcns_owner, }; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index e9e4427..2665b58 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -6421,12 +6421,18 @@ static void cgroupns_put(struct ns_common *ns) put_cgroup_ns(to_cg_ns(ns)); } +static struct user_namespace *cgroupns_owner(struct ns_common *ns) +{ + return to_cg_ns(ns)->user_ns; +} + const struct proc_ns_operations cgroupns_operations = { .name = "cgroup", .type = CLONE_NEWCGROUP, .get = cgroupns_get, .put = cgroupns_put, .install = cgroupns_install, + .owner = cgroupns_owner, }; static __init int cgroup_namespaces_init(void) diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index 30a7f33..c18f0f4f 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -405,12 +405,18 @@ static int pidns_install(struct nsproxy *nsproxy, struct ns_common *ns) return 0; } +static struct user_namespace *pidns_owner(struct ns_common *ns) +{ + return to_pid_ns(ns)->user_ns; +} + const struct proc_ns_operations pidns_operations = { .name = "pid", .type = CLONE_NEWPID, .get = pidns_get, .put = pidns_put, .install = pidns_install, + .owner = pidns_owner, }; static __init int pid_namespaces_init(void) diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 0edafe3..42a64d5 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -1050,12 +1050,36 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns) return commit_creds(cred); } +struct ns_common *ns_get_owner(struct ns_common *ns) +{ + struct user_namespace *my_user_ns = current_user_ns(); + struct user_namespace *owner, *p; + + /* See if the owner is in the current user namespace */ + owner = p = ns->ops->owner(ns); + for (;;) { + if (!p) + return ERR_PTR(-EPERM); + if (p == my_user_ns) + break; + p = p->parent; + } + + return &get_user_ns(owner)->ns; +} + +static struct user_namespace *userns_owner(struct ns_common *ns) +{ + return to_user_ns(ns)->parent; +} + const struct proc_ns_operations userns_operations = { .name = "user", .type = CLONE_NEWUSER, .get = userns_get, .put = userns_put, .install = userns_install, + .owner = userns_owner, }; static __init int user_namespaces_init(void) diff --git a/kernel/utsname.c b/kernel/utsname.c index f3b0bb4..0795e97 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c @@ -154,10 +154,16 @@ static int utsns_install(struct nsproxy *nsproxy, struct ns_common *new) return 0; } +static struct user_namespace *utsns_owner(struct ns_common *ns) +{ + return to_uts_ns(ns)->user_ns; +} + const struct proc_ns_operations utsns_operations = { .name = "uts", .type = CLONE_NEWUTS, .get = utsns_get, .put = utsns_put, .install = utsns_install, + .owner = utsns_owner, }; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 3e2812a..8619e89 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -1016,11 +1016,17 @@ static int netns_install(struct nsproxy *nsproxy, struct ns_common *ns) return 0; } +static struct user_namespace *netns_owner(struct ns_common *ns) +{ + return to_net_ns(ns)->user_ns; +} + const struct proc_ns_operations netns_operations = { .name = "net", .type = CLONE_NEWNET, .get = netns_get, .put = netns_put, .install = netns_install, + .owner = netns_owner, }; #endif -- 2.5.5