From patchwork Fri Aug 26 23:08:08 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrey Vagin X-Patchwork-Id: 9302113 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 0D653607D8 for ; Fri, 26 Aug 2016 23:09:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F10F029593 for ; Fri, 26 Aug 2016 23:09:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E508629653; Fri, 26 Aug 2016 23:09:28 +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 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 61FC929593 for ; Fri, 26 Aug 2016 23:09:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754619AbcHZXIj (ORCPT ); Fri, 26 Aug 2016 19:08:39 -0400 Received: from mail-pa0-f67.google.com ([209.85.220.67]:33792 "EHLO mail-pa0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752315AbcHZXIh (ORCPT ); Fri, 26 Aug 2016 19:08:37 -0400 Received: by mail-pa0-f67.google.com with SMTP id hh10so5357187pac.1; Fri, 26 Aug 2016 16:08:37 -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=0NIHOVWUgj82DDHK9MGSsLllEKNh5UDfkRKfffTuqJY=; b=ScN4k/I5dJUO33Ro9moi3RN2+YA+asH0T6sGxp/ckkcbNLXZiFJWNaYLm/oFhSuX8C zCe18xbg7npypruCGBog7GU4DDhDSameY38VsM0UiFAoh1noWBayrzxtgu+LD5bFKX9A OOhi19NRtn8PpmmTOtC1sUfpOb482MQyO+yXwAE7uMu7fvtp9o5ihsCz3moRj/0D8JZn j3Za/DH4ou75J2eTjJ+hhopDcp4gXpeSfuPMmgDmmPFS1VTe141ggB42Mxdlz4VgCvBj YGOTo+0msVFKB5R9xWC/nEI6lx3wRlwU5U7F8wDSrqLoQWa/eI25kj8+5+/tNCGSBNlR rqKw== 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=0NIHOVWUgj82DDHK9MGSsLllEKNh5UDfkRKfffTuqJY=; b=fIFcK+iZ+Qx+tTGK6MvjIvA7MvVYJyQxDoVooxXTv+KHw0ff9IOtMCj3JKNtxlKEgx +7JxP1Mgdd58RpKTxydS9lEe6LAYxljdKqAScyWZMgKzyaquqJmfobyXDt40lci0ETuo oeo2bweTWWEtk95xxMyRASyYIqIUeVSMb7lECC9kDBxwJBmEZH2gT17++rUXge8S2BwK EkFzeoiOjzbxD8hSwTUTj90GFX16L5DTnQHhwQIMIB+rkFmwN5oBiegIx4Aud7whoKIa pmhsi59Ee73QuofSBKH1XgnR0wns5305WYGhtn1P7dFasAEdKDJ2RYpipMbYjOZWPKU8 zmoA== X-Gm-Message-State: AE9vXwNgauDsWnHOQRN5QVcnrcBwz5GGF+JotrTzTueD8H/M6M8LgBAbR/HptsDuNb1MOg== X-Received: by 10.66.12.102 with SMTP id x6mr10242243pab.48.1472252916660; Fri, 26 Aug 2016 16:08:36 -0700 (PDT) Received: from laptop.vz.com ([162.246.95.100]) by smtp.gmail.com with ESMTPSA id ro14sm31245680pab.32.2016.08.26.16.08.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 26 Aug 2016 16:08:35 -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: Fri, 26 Aug 2016 16:08:08 -0700 Message-Id: <1472252891-4963-2-git-send-email-avagin@openvz.org> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1472252891-4963-1-git-send-email-avagin@openvz.org> References: <1472252891-4963-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. 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; +} + const struct proc_ns_operations mntns_operations = { .name = "mnt", .type = CLONE_NEWNS, .get = mntns_get, .put = mntns_put, .install = mntns_install, + .get_owner = mntns_get_owner, }; diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h index de0e771..cfc8be7 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 *(*get_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..991a31e 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_get_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, + .get_owner = ipcns_get_owner, }; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index e9e4427..4204693 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_get_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, + .get_owner = cgroupns_get_owner, }; static __init int cgroup_namespaces_init(void) diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index 30a7f33..1860d9d 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_get_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, + .get_owner = pidns_get_owner, }; static __init int pid_namespaces_init(void) diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 0edafe3..f0521e4 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->get_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_get_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, + .get_owner = userns_get_owner, }; static __init int user_namespaces_init(void) diff --git a/kernel/utsname.c b/kernel/utsname.c index f3b0bb4..3b3028f 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_get_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, + .get_owner = utsns_get_owner, }; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 3e2812a..1ccba4b 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_get_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, + .get_owner = netns_get_owner, }; #endif