From patchwork Fri Aug 26 23:08:09 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrey Vagin X-Patchwork-Id: 9302117 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 0380C60757 for ; Fri, 26 Aug 2016 23:09:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E6ECB29593 for ; Fri, 26 Aug 2016 23:09:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D83302966A; Fri, 26 Aug 2016 23:09:46 +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 61EB929593 for ; Fri, 26 Aug 2016 23:09:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932247AbcHZXJd (ORCPT ); Fri, 26 Aug 2016 19:09:33 -0400 Received: from mail-pf0-f196.google.com ([209.85.192.196]:36794 "EHLO mail-pf0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754196AbcHZXIi (ORCPT ); Fri, 26 Aug 2016 19:08:38 -0400 Received: by mail-pf0-f196.google.com with SMTP id y134so5558354pfg.3; 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=eNsPbAuz4uNRu3jObAMv4dMqt14r9N5rGxzMHHdls7w=; b=qnKgPHcSe7+j70qjwPaZjTFYCd0lSSNI/whhWX8+HGPmhdp/EIz4GFS3Cpqdaj+0iE L9O39Rchk7HEyRaYZDINLDHOdMkFziJUGb3lcSTzLf0X2LFVD+VxZGna2NG/SdoJfLKT 0wStLx79mgbcdUF7M7UoTsyBMyxqeJ6n62FW+RyzAxI4P6tAVI7KH7CRNpWd2oifZT8R ZToC7Hkx/3QWm3bLFCDhx+hxPom3Wtidg3m+XsZikHcDSJMfJuYBtthUjL6ksyDH+HT2 I9jB6/z8qtyT+WISj98fxvWfTBD26Sd9ctYiOHpbKtxF5ix8ATIcVfRhCjaZEJdip4Yh 7YTQ== 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=eNsPbAuz4uNRu3jObAMv4dMqt14r9N5rGxzMHHdls7w=; b=Ea1/AXCVw3A/1+LIuDj6HauKq+Qa4IQ1mmeRnH+PobvqJPnc7mD9zsekV0IAPMg/vi b/hdSdfiYnob+iG+Z3NvIPMY71j5EqMak6OjXM8Bab3F3smAeImHJcroFvZsGwSERhqV kkQDTj0uOQP7Suz6QLf7P/M008OGEr6cKwcFdVV2DV08z9dk0j+4D6qsMl/HZ1qRqjo4 F0ioSXECNQOvNAKIn8C4rdWTTYonIAgtSX/3H8SnjlGctXUmTnWuHKcfckO4hz4Htkae 7+0HAxQie7cOn0jjL3sUzpZPsfR757ye7oplt23KF4oxyiyYXyMEfJO1GfbRVgfG1G7L mQpA== X-Gm-Message-State: AE9vXwPszzedrEJ9i1iZKrwShEx4Y6PLOcGgwatfJjgON8mXpv3OZd4ZXCmPE3Pp73vd3Q== X-Received: by 10.98.102.221 with SMTP id s90mr10281591pfj.69.1472252917376; Fri, 26 Aug 2016 16:08:37 -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.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 26 Aug 2016 16:08:36 -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 2/4] nsfs: add ioctl to get an owning user namespace for ns file descriptor Date: Fri, 26 Aug 2016 16:08:09 -0700 Message-Id: <1472252891-4963-3-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 Each namespace has an owning user namespace and now there is not way to discover these relationships. Understending namespaces relationships allows to answer the question: what capability does process X have to perform operations on a resource governed by namespace Y? After a long discussion, Eric W. Biederman proposed to use ioctl-s for this purpose. The NS_GET_USERNS ioctl returns a file descriptor to an owning user namespace. It returns EPERM if a target namespace is outside of a current user namespace. v2: rename parent to relative Link: https://lkml.org/lkml/2016/7/6/158 Signed-off-by: Andrei Vagin --- fs/nsfs.c | 95 ++++++++++++++++++++++++++++++++++++++++------- include/uapi/linux/nsfs.h | 11 ++++++ 2 files changed, 93 insertions(+), 13 deletions(-) create mode 100644 include/uapi/linux/nsfs.h diff --git a/fs/nsfs.c b/fs/nsfs.c index 8f20d60..be7d193 100644 --- a/fs/nsfs.c +++ b/fs/nsfs.c @@ -5,11 +5,16 @@ #include #include #include +#include +#include static struct vfsmount *nsfs_mnt; +static long ns_ioctl(struct file *filp, unsigned int ioctl, + unsigned long arg); static const struct file_operations ns_file_operations = { .llseek = no_llseek, + .unlocked_ioctl = ns_ioctl, }; static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) @@ -44,22 +49,14 @@ static void nsfs_evict(struct inode *inode) ns->ops->put(ns); } -void *ns_get_path(struct path *path, struct task_struct *task, - const struct proc_ns_operations *ns_ops) +static void *__ns_get_path(struct path *path, struct ns_common *ns) { struct vfsmount *mnt = mntget(nsfs_mnt); struct qstr qname = { .name = "", }; struct dentry *dentry; struct inode *inode; - struct ns_common *ns; unsigned long d; -again: - ns = ns_ops->get(task); - if (!ns) { - mntput(mnt); - return ERR_PTR(-ENOENT); - } rcu_read_lock(); d = atomic_long_read(&ns->stashed); if (!d) @@ -68,7 +65,7 @@ again: if (!lockref_get_not_dead(&dentry->d_lockref)) goto slow; rcu_read_unlock(); - ns_ops->put(ns); + ns->ops->put(ns); got_it: path->mnt = mnt; path->dentry = dentry; @@ -77,7 +74,7 @@ slow: rcu_read_unlock(); inode = new_inode_pseudo(mnt->mnt_sb); if (!inode) { - ns_ops->put(ns); + ns->ops->put(ns); mntput(mnt); return ERR_PTR(-ENOMEM); } @@ -95,17 +92,89 @@ slow: return ERR_PTR(-ENOMEM); } d_instantiate(dentry, inode); - dentry->d_fsdata = (void *)ns_ops; + dentry->d_fsdata = (void *)ns->ops; d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry); if (d) { d_delete(dentry); /* make sure ->d_prune() does nothing */ dput(dentry); cpu_relax(); - goto again; + return ERR_PTR(-EAGAIN); } goto got_it; } +void *ns_get_path(struct path *path, struct task_struct *task, + const struct proc_ns_operations *ns_ops) +{ + struct ns_common *ns; + void *ret; + +again: + ns = ns_ops->get(task); + if (!ns) + return ERR_PTR(-ENOENT); + + ret = __ns_get_path(path, ns); + if (IS_ERR(ret) && PTR_ERR(ret) == -EAGAIN) + goto again; + return ret; +} + +static int open_related_ns(struct ns_common *ns, + struct ns_common *(*get_ns)(struct ns_common *ns)) +{ + struct path path = {}; + struct file *f; + void *err; + int fd; + + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) + return fd; + + while (1) { + struct ns_common *relative; + + relative = get_ns(ns); + if (IS_ERR(relative)) { + put_unused_fd(fd); + return PTR_ERR(relative); + } + + err = __ns_get_path(&path, relative); + if (IS_ERR(err) && PTR_ERR(err) == -EAGAIN) + continue; + break; + } + if (IS_ERR(err)) { + put_unused_fd(fd); + return PTR_ERR(err); + } + + f = dentry_open(&path, O_RDONLY, current_cred()); + path_put(&path); + if (IS_ERR(f)) { + put_unused_fd(fd); + fd = PTR_ERR(f); + } else + fd_install(fd, f); + + return fd; +} + +static long ns_ioctl(struct file *filp, unsigned int ioctl, + unsigned long arg) +{ + struct ns_common *ns = get_proc_ns(file_inode(filp)); + + switch (ioctl) { + case NS_GET_USERNS: + return open_related_ns(ns, ns_get_owner); + default: + return -ENOTTY; + } +} + int ns_get_name(char *buf, size_t size, struct task_struct *task, const struct proc_ns_operations *ns_ops) { diff --git a/include/uapi/linux/nsfs.h b/include/uapi/linux/nsfs.h new file mode 100644 index 0000000..5cacd5c --- /dev/null +++ b/include/uapi/linux/nsfs.h @@ -0,0 +1,11 @@ +#ifndef __LINUX_NSFS_H +#define __LINUX_NSFS_H + +#include + +#define NSIO 0xb7 + +/* Returns a file descriptor that refers to an owning user namespace */ +#define NS_GET_USERNS _IO(NSIO, 0x1) + +#endif /* __LINUX_NSFS_H */