From patchwork Thu Nov 1 21:48:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Seth Forshee X-Patchwork-Id: 10664557 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 37BB917D5 for ; Thu, 1 Nov 2018 21:49:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 285402C1F6 for ; Thu, 1 Nov 2018 21:49:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1C6B62C3D2; Thu, 1 Nov 2018 21:49:24 +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.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI 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 978C22C1F6 for ; Thu, 1 Nov 2018 21:49:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727977AbeKBGyD (ORCPT ); Fri, 2 Nov 2018 02:54:03 -0400 Received: from youngberry.canonical.com ([91.189.89.112]:58275 "EHLO youngberry.canonical.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727835AbeKBGyD (ORCPT ); Fri, 2 Nov 2018 02:54:03 -0400 Received: from mail-it1-f200.google.com ([209.85.166.200]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1gIKq2-0008KT-Iu for linux-fsdevel@vger.kernel.org; Thu, 01 Nov 2018 21:49:14 +0000 Received: by mail-it1-f200.google.com with SMTP id n135-v6so497750ita.0 for ; Thu, 01 Nov 2018 14:49:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ssHBrVY4nRWUii0FegPmCz0YBObhDZI10ZPtWTEhtfI=; b=OnE4Vh/kQnU2VT6Iotgsrz4WQLSXJCA18X6QwHn4Bnmh/Yn4+fPCdVJYJ5IHUGkIOx CbI1pXUL7GjTiFG+r6huJt67Uv7wKlDJ9jh6xs/npDZlq64+Pl9rB3E3QE609G+Bwuzq Pkbrqys7JtTj0MTdTiIsn4Cv9CbIghmtOnX8nbFKqAhOWwsNpozahjXWsxaUdtK3GiGT APoGoa9Wh64oGGPv7bvlHjjzSp67LNj5FAEvR2UAlIUWmCCgH5lk4mTAp30o+E/87LdR 2Ciibw3sV3ZzwgSs2+bcLbYHRIm+CrJzxBCC5bWAzM0SmjClaT3t+nZIm/WLUjCCEQfI O9jg== X-Gm-Message-State: AGRZ1gLwWEaswUbgvoM48yUzhPTGHPKSjcsRJF9NmFWDdSxw6yw+2tD4 3Lgd3vanyA3mb/F2yqVK680oPyZql6qtvyY9sxLrTB7sEoogWfnh2gdNguKq4onVTBfl+LGnf+i 4ao5INcSW9FHVzCKFXX56ki2U82ilX25n1CUKs0nzK8Y= X-Received: by 2002:a02:b45a:: with SMTP id w26-v6mr7736307jaj.45.1541108953133; Thu, 01 Nov 2018 14:49:13 -0700 (PDT) X-Google-Smtp-Source: AJdET5dDaKJBrDdhw3VjHDkfjLz9RNuSjLwQJnSQr8NDzg7HqjE4SQHD+0DRV/mB/BZFSFmo+fiPXg== X-Received: by 2002:a02:b45a:: with SMTP id w26-v6mr7736291jaj.45.1541108952698; Thu, 01 Nov 2018 14:49:12 -0700 (PDT) Received: from localhost ([2605:a601:ac7:2a20:7c8b:4047:a2ef:69cd]) by smtp.gmail.com with ESMTPSA id o10-v6sm9449349iob.43.2018.11.01.14.49.11 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 01 Nov 2018 14:49:11 -0700 (PDT) From: Seth Forshee To: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, containers@lists.linux-foundation.org, James Bottomley Subject: [RFC PATCH 6/6] shiftfs: support nested shiftfs mounts Date: Thu, 1 Nov 2018 16:48:56 -0500 Message-Id: <20181101214856.4563-7-seth.forshee@canonical.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181101214856.4563-1-seth.forshee@canonical.com> References: <20181101214856.4563-1-seth.forshee@canonical.com> 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 shiftfs mounts cannot be nested for two reasons -- global CAP_SYS_ADMIN is required to set up a mark mount, and a single functional shiftfs mount meets the filesystem stacking depth limit. The CAP_SYS_ADMIN requirement can be relaxed. All of the kernel ids in a mount must be within that mount's s_user_ns, so all that is needed is CAP_SYS_ADMIN within that s_user_ns. The stack depth issue can be worked around with a couple of adjustments. First, a mark mount doesn't really need to count against the stacking depth as it doesn't contribute to the call stack depth during filesystem operations. Therefore the mount over the mark mount only needs to count as one more than the lower filesystems stack depth. Second, when the lower mount is shiftfs we can just skip down to that mount's lower filesystem and shift ids relative to that. There is no reason to shift ids twice, and the lower path has already been marked safe for id shifting by a user privileged towards all ids in that mount's user ns. Signed-off-by: Seth Forshee --- fs/shiftfs.c | 68 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/fs/shiftfs.c b/fs/shiftfs.c index b19af7b2fe75..008ace2842b9 100644 --- a/fs/shiftfs.c +++ b/fs/shiftfs.c @@ -930,7 +930,7 @@ static int shiftfs_fill_super(struct super_block *sb, void *raw_data, struct shiftfs_data *data = raw_data; char *name = kstrdup(data->path, GFP_KERNEL); int err = -ENOMEM; - struct shiftfs_super_info *ssi = NULL; + struct shiftfs_super_info *ssi = NULL, *mp_ssi; struct path path; struct dentry *dentry; @@ -946,11 +946,7 @@ static int shiftfs_fill_super(struct super_block *sb, void *raw_data, if (err) goto out; - /* to mark a mount point, must be real root */ - if (ssi->mark && !capable(CAP_SYS_ADMIN)) - goto out; - - /* else to mount a mark, must be userns admin */ + /* to mount a mark, must be userns admin */ if (!ssi->mark && !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) goto out; @@ -962,41 +958,66 @@ static int shiftfs_fill_super(struct super_block *sb, void *raw_data, if (!S_ISDIR(path.dentry->d_inode->i_mode)) { err = -ENOTDIR; - goto out_put; - } - - sb->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; - if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { - printk(KERN_ERR "shiftfs: maximum stacking depth exceeded\n"); - err = -EINVAL; - goto out_put; + goto out_put_path; } if (ssi->mark) { + struct super_block *lower_sb = path.mnt->mnt_sb; + + /* to mark a mount point, must root wrt lower s_user_ns */ + if (!ns_capable(lower_sb->s_user_ns, CAP_SYS_ADMIN)) + goto out_put_path; + + /* * this part is visible unshifted, so make sure no * executables that could be used to give suid * privileges */ sb->s_iflags = SB_I_NOEXEC; - ssi->mnt = path.mnt; - dentry = path.dentry; - } else { - struct shiftfs_super_info *mp_ssi; + /* + * Handle nesting of shiftfs mounts by referring this mark + * mount back to the original mark mount. This is more + * efficient and alleviates concerns about stack depth. + */ + if (lower_sb->s_magic == SHIFTFS_MAGIC) { + mp_ssi = lower_sb->s_fs_info; + + /* Doesn't make sense to mark a mark mount */ + if (mp_ssi->mark) { + err = -EINVAL; + goto out_put_path; + } + + ssi->mnt = mntget(mp_ssi->mnt); + dentry = dget(path.dentry->d_fsdata); + } else { + ssi->mnt = mntget(path.mnt); + dentry = dget(path.dentry); + } + } else { /* * this leg executes if we're admin capable in * the namespace, so be very careful */ if (path.dentry->d_sb->s_magic != SHIFTFS_MAGIC) - goto out_put; + goto out_put_path; mp_ssi = path.dentry->d_sb->s_fs_info; if (!mp_ssi->mark) - goto out_put; + goto out_put_path; ssi->mnt = mntget(mp_ssi->mnt); dentry = dget(path.dentry->d_fsdata); - path_put(&path); } + + sb->s_stack_depth = dentry->d_sb->s_stack_depth + 1; + if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { + printk(KERN_ERR "shiftfs: maximum stacking depth exceeded\n"); + err = -EINVAL; + goto out_put_mnt; + } + + path_put(&path); ssi->userns = get_user_ns(dentry->d_sb->s_user_ns); sb->s_fs_info = ssi; sb->s_magic = SHIFTFS_MAGIC; @@ -1009,7 +1030,10 @@ static int shiftfs_fill_super(struct super_block *sb, void *raw_data, return 0; - out_put: + out_put_mnt: + mntput(ssi->mnt); + dput(dentry); + out_put_path: path_put(&path); out: kfree(name);