From patchwork Wed Apr 26 21:35:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amir Goldstein X-Patchwork-Id: 9702101 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 3AD6E603F7 for ; Wed, 26 Apr 2017 21:35:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2AE792858E for ; Wed, 26 Apr 2017 21:35:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1F963285EE; Wed, 26 Apr 2017 21:35: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=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, 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 9F74B2858E for ; Wed, 26 Apr 2017 21:35:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1030899AbdDZVfh (ORCPT ); Wed, 26 Apr 2017 17:35:37 -0400 Received: from mail-wr0-f195.google.com ([209.85.128.195]:32913 "EHLO mail-wr0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754425AbdDZVf3 (ORCPT ); Wed, 26 Apr 2017 17:35:29 -0400 Received: by mail-wr0-f195.google.com with SMTP id w50so1681988wrc.0; Wed, 26 Apr 2017 14:35:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Ukc1DsmhwZMnv7QiTyJL8Ax25VxEwcj/sdQO//SkzZY=; b=fYpCjM8uqOPvRolDPxGcybydQDFfTLrNt+gLn/47iNOw9Cw+UNST8UityNp8nKNKum xNSTl6AWrTmfdtkmsh8E/5im4HvCLC++oe/0PHtZQsqoWsswoucgnnuKf4K6UXTTT8Ub Xh0b0A7Cn3pkRNdIcNtz+Y/MiHEnc40soYia4caKXG6sTEtqG7Yz1JKhy5sVibIQaD9S Jb67jdemF1RSv3CyEgQA60Z5/xEgcOLnW3eP2iYQjGF38e+bnCwOjqp/tsdIYewnNp0C rqgrFiplDJ9lK8xR+QWy1G8H2VGa2aWDCkXvZJYl5plCigf55YJMu71XrITBx1WucvJv OTYQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Ukc1DsmhwZMnv7QiTyJL8Ax25VxEwcj/sdQO//SkzZY=; b=NreVPldHMBv2m8GX9S1Jy6QHCX7Gw9QETFrMRkipelh06IF2uFWzhjls6gzU3rnBgW s2oilSVW+WkvzvszT+T8+FLkzMr8CrVwtyz1KZFIJRB5ooJomH/K8zm+IVpH53H66Nwu Z0ktIdgHqBMkRNRWMTZS38DUOwHq8lIxcRlsbkSC97g8RngX1J3QEYSivESeSeFLFrZa afLIm9ISxh3mfmOyuSZGClNYrYmm7+zf/NlhkhxP6kuvpMrSUoLL+w3GmPJKFd+ZDTpc Njg1uiIEdfIgnAB/8M1aLZQ2AILDUQnxkSNSGyEyK0JRZ+qA1eFZplSyQ6mTJiySflN2 RvLQ== X-Gm-Message-State: AN3rC/5zsFTeoibZtNpUGpIg7y63XWqGHUiOlZ/LX8QR59M+UIwNh432 CQ2/krjOJV11Ug== X-Received: by 10.223.168.120 with SMTP id l111mr1116332wrc.137.1493242522185; Wed, 26 Apr 2017 14:35:22 -0700 (PDT) Received: from amir-VirtualBox.lan (bzq-79-179-55-127.red.bezeqint.net. [79.179.55.127]) by smtp.gmail.com with ESMTPSA id 81sm931577wmj.9.2017.04.26.14.35.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 26 Apr 2017 14:35:21 -0700 (PDT) From: Amir Goldstein To: Miklos Szeredi Cc: Vivek Goyal , Al Viro , linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH v3 08/16] ovl: validate lower layer uuid and root on redirect by fh Date: Thu, 27 Apr 2017 00:35:10 +0300 Message-Id: <1493242518-15266-9-git-send-email-amir73il@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1493242518-15266-1-git-send-email-amir73il@gmail.com> References: <1493242518-15266-1-git-send-email-amir73il@gmail.com> 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 copy up, we store xattr overlay.origin.uuid and overlay.origin.root along with overlay.origin.fh. Before decoding the file handle at overlay.origin.fh verify: - All lower layers are on the same fs - UUID of lower fs matches the stored uuid If there are more than one lower layer, find the lower layer mount in which origin.fh should be decoded by decoding origin.root and matching the result to a lower layer root dentry. Signed-off-by: Amir Goldstein --- fs/overlayfs/namei.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index 28d54e3..970d8158 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -27,6 +27,8 @@ struct ovl_lookup_data { char *redirect; /* - path to follow */ bool by_fh; /* redirect by file handle: */ struct ovl_fh *fh; /* - file handle to follow */ + struct ovl_fh *rootfh; /* - file handle of layer root */ + unsigned char uuid[16]; /* - uuid of layer filesystem */ }; static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d, @@ -121,8 +123,24 @@ static struct ovl_fh *ovl_get_fh(struct dentry *dentry, const char *name) static int ovl_check_redirect_fh(struct dentry *dentry, struct ovl_lookup_data *d) { + int res; + kfree(d->fh); d->fh = ovl_get_fh(dentry, OVL_XATTR_ORIGIN_FH); + kfree(d->rootfh); + d->rootfh = ovl_get_fh(dentry, OVL_XATTR_ORIGIN_ROOT); + + res = vfs_getxattr(dentry, OVL_XATTR_ORIGIN_UUID, d->uuid, + sizeof(d->uuid)); + if (res == sizeof(d->uuid)) + return 0; + + if (res != -ENODATA && res != -EOPNOTSUPP) { + pr_warn_ratelimited("overlayfs: failed to get %s (%i)\n", + OVL_XATTR_ORIGIN_UUID, res); + } + + memset(d->uuid, 0, sizeof(d->uuid)); return 0; } @@ -130,6 +148,9 @@ static void ovl_reset_redirect_fh(struct ovl_lookup_data *d) { kfree(d->fh); d->fh = NULL; + kfree(d->rootfh); + d->rootfh = NULL; + memset(d->uuid, 0, sizeof(d->uuid)); } static bool ovl_is_opaquedir(struct dentry *dentry) @@ -309,6 +330,53 @@ static int ovl_lookup_layer_fh(struct vfsmount *mnt, struct ovl_lookup_data *d, return ovl_lookup_data(this, d, 0, "", ret); } +static int ovl_is_dir(void *ctx, struct dentry *dentry) +{ + return d_is_dir(dentry); +} + +/* Find lower layer index by layer root file handle and uuid */ +static int ovl_find_layer_by_fh(struct dentry *dentry, struct ovl_lookup_data *d) +{ + struct ovl_entry *roe = dentry->d_sb->s_root->d_fsdata; + struct super_block *lower_sb = ovl_same_lower_sb(dentry->d_sb); + struct dentry *this; + int i; + + /* + * For now, we only support lookup by fh for all lower layers on the + * same sb. Not all filesystems set sb->s_uuid. For those who don't + * this code will compare zeros, which at least ensures us that the + * file handles are not crossing from filesystem with sb->s_uuid to + * a filesystem without sb->s_uuid and vice versa. + */ + if (!lower_sb || memcmp(lower_sb->s_uuid, &d->uuid, sizeof(d->uuid))) + return -1; + + /* Don't bother verifying rootfh with a single lower layer */ + if (roe->numlower == 1) + return 0; + + /* + * Layer root dentries are pinned, there are no aliases for dirs, and + * all lower layers are on the same sb. If rootfh is correct, + * exportfs_decode_fh() will find it in dcache and return the only + * instance, regardless of the mnt argument and we can compare the + * returned pointer with the pointers in lowerstack. + */ + this = ovl_decode_fh(roe->lowerstack[0].mnt, d->rootfh, ovl_is_dir); + if (IS_ERR(this)) + return -1; + + for (i = 0; i < roe->numlower; i++) { + if (this == roe->lowerstack[i].dentry) + break; + } + + dput(this); + return i < roe->numlower ? i : -1; +} + /* * Returns next layer in stack starting from top. * Returns -1 if this is the last layer. @@ -357,6 +425,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, .redirect = NULL, .by_fh = true, .fh = NULL, + .rootfh = NULL, }; if (dentry->d_name.len > ofs->namelen) @@ -405,8 +474,13 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, /* Try to lookup lower layers by file handle */ d.by_path = false; if (!d.stop && d.fh) { - struct vfsmount *lowermnt = roe->lowerstack[0].mnt; + struct vfsmount *lowermnt; + int layer = ovl_find_layer_by_fh(dentry, &d); + + if (layer < 0 || layer >= roe->numlower) + goto lookup_by_path; + lowermnt = roe->lowerstack[layer].mnt; d.last = true; err = ovl_lookup_layer_fh(lowermnt, &d, &this); if (err)