From patchwork Tue Sep 6 07:47:13 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrey Vagin X-Patchwork-Id: 9315867 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 898E1601C0 for ; Tue, 6 Sep 2016 07:49:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8DC8B28BD0 for ; Tue, 6 Sep 2016 07:49:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8264828BD2; Tue, 6 Sep 2016 07:49: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=-4.4 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID 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 5D22C28BD0 for ; Tue, 6 Sep 2016 07:49:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755808AbcIFHsw (ORCPT ); Tue, 6 Sep 2016 03:48:52 -0400 Received: from mail-lf0-f67.google.com ([209.85.215.67]:34931 "EHLO mail-lf0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755260AbcIFHrl (ORCPT ); Tue, 6 Sep 2016 03:47:41 -0400 Received: by mail-lf0-f67.google.com with SMTP id s64so603857lfs.2; Tue, 06 Sep 2016 00:47:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=C+u2VFNOKrB2yKEbPSGv/lKdMWwQp08ouwQlFDiyquk=; b=1ELvwtWvj87yC4dCp/meaLY10npzDuFmVrDM1MV7EHxsCpS1oOe8KYj08U2PjDvRXi LcQwrydCzDLzoJDGm02owLZVdoArfIe5Nnob/FfTDWkSAbraWwS1Mv6JxFqzg6q++coU 4Dbv6Ku9JpyHv/PO9ZAoP3CAlVVIq39JU3pNZJ7KDq3mLWEmQZq7yoETK14t6bXHsOYx Arlf6NzWbrK9Fhd8BtatGW+p4TqSbDo4D643x9m0YH8epZInNB8pIST4BE9G8QA7xSn8 2N9aHmvE5oaDpwBiyqld4FgpCaroGbmfYLvR8Oqtnl404RxxZrVBhghsF4dS/i9euvS0 pCKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=C+u2VFNOKrB2yKEbPSGv/lKdMWwQp08ouwQlFDiyquk=; b=heZQGPO95InAvTbsJ9gGTfATyCtTR7E6HZNVjyxaxKIJpvi3cPkKAscOHkbtBmWHYa oJf4aDWBRPGjISprXpQwCxzfjav8AtBJTJZVeVyuMGD/rm5j7rXjiY8WDTv++Ji3OJQO zZXefFPFnDiYEj9orAUPk4y5Ov8i852MSVawsapjkHZYmFpC5xaM1dhpEQUHx4mw6HmU eh2v6PdDkAAh/tmYOPyZeMqFoyj78CdOONe1n57r6WFRPG0WzmvB21iXCWREj5ihMsLd jMrVseOQp8mB2lTfAyDG5J3XNu3L+jao2epgF+Ps6QNiKN3FqQAGT5LOoRN/csFt6ufD bp8w== X-Gm-Message-State: AE9vXwPNdNr21jTCzQYLNGEphdMmgpM5ijQduLmwrKp13M1ioeHgyLF9BmkI/TAauuW12w== X-Received: by 10.25.150.208 with SMTP id y199mr12048321lfd.92.1473148059341; Tue, 06 Sep 2016 00:47:39 -0700 (PDT) Received: from laptop.sw.ru (swsoft-msk-nat.sw.ru. [195.214.232.10]) by smtp.gmail.com with ESMTPSA id e73sm5352388lji.31.2016.09.06.00.47.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 06 Sep 2016 00:47:38 -0700 (PDT) From: Andrei Vagin To: "Eric W. Biederman" , containers@lists.linux-foundation.org Cc: linux-api@vger.kernel.org, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, Andrey Vagin , James Bottomley , "Michael Kerrisk (man-pages)" , "W. Trevor King" , Alexander Viro , Serge Hallyn Subject: [PATCH 1/4] kernel: add a helper to get an owning user namespace for a namespace Date: Tue, 6 Sep 2016 00:47:13 -0700 Message-Id: <1473148036-32630-2-git-send-email-avagin@openvz.org> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1473148036-32630-1-git-send-email-avagin@openvz.org> References: <1473148036-32630-1-git-send-email-avagin@openvz.org> 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 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. v3: rename ns->get_owner() to ns->owner(). get_* usually means that it grabs a reference. Acked-by: Serge Hallyn 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