Re: [PATCH v15 10/30] ovl: Modify ovl_lookup() and friends to lookup metacopy dentry

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, May 11, 2018 at 5:30 PM, Vivek Goyal <vgoyal@xxxxxxxxxx> wrote:
> Hi Miklos, Amir,
>
> Please find attached V2 of the patch. I have taken care of comments. I
> have again pushed latest patches on metacopy-next branch.
>
> https://github.com/rhvgoyal/linux/commits/metacopy-next
>
> Changes:
> - Use EIO instead of ESTALE at few places.
> - Make sure metacopy dentry or data dentry is a regular file.
> - Modified ovl_lookup_single() for better error handling of bad
>   redirects (Miklos's feedback).
> - In ovl_lookup(), for non-dir, if lower does not match against ORIGIN,
>   then we error out only if index=on. Otherwise we continue to use the
>   dentry found by path based lookup.
>
> Thanks
> Vivek
>
> Subject: ovl: Modify ovl_lookup() and friends to lookup metacopy dentry
>
> This patch modifies ovl_lookup() and friends to lookup metacopy dentries.
> It also allows for presence of metacopy dentries in lower layer.
>
> During lookup, check for presence of OVL_XATTR_METACOPY and if not present,
> set OVL_UPPERDATA bit in flags.
>
> We don't support metacopy feature with nfs_export. So in nfs_export code,
> we set OVL_UPPERDATA flag set unconditionally if upper inode exists.
>
> Do not follow metacopy origin if we find a metacopy only inode and metacopy
> feature is not enabled for that mount. Like redirect, this can have security
> implications where an attacker could hand craft upper and try to gain
> access to file on lower which it should not have to begin with.
>
> Signed-off-by: Vivek Goyal <vgoyal@xxxxxxxxxx>
> Reviewed-by: Amir Goldstein <amir73il@xxxxxxxxx>
> ---
>  fs/overlayfs/export.c    |    3 +
>  fs/overlayfs/inode.c     |   11 +++-
>  fs/overlayfs/namei.c     |  125 ++++++++++++++++++++++++++++++++++++++++-------
>  fs/overlayfs/overlayfs.h |    1
>  fs/overlayfs/util.c      |   22 ++++++++
>  5 files changed, 143 insertions(+), 19 deletions(-)
>
> Index: rhvgoyal-linux/fs/overlayfs/namei.c
> ===================================================================
> --- rhvgoyal-linux.orig/fs/overlayfs/namei.c    2018-05-10 15:53:00.858878145 -0400
> +++ rhvgoyal-linux/fs/overlayfs/namei.c 2018-05-11 09:17:38.751646662 -0400
> @@ -24,6 +24,7 @@ struct ovl_lookup_data {
>         bool stop;
>         bool last;
>         char *redirect;
> +       bool metacopy;
>  };
>
>  static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d,
> @@ -253,19 +254,33 @@ static int ovl_lookup_single(struct dent
>                 goto put_and_out;
>         }
>         if (!d_can_lookup(this)) {
> -               d->stop = true;
> -               if (d->is_dir)
> +               if (d->is_dir || !last_element) {
> +                       d->stop = true;
>                         goto put_and_out;
> -
> +               }
> +               err = ovl_check_metacopy_xattr(this);
> +               if (err < 0)
> +                       goto out_err;
>                 /*
> -                * NB: handle failure to lookup non-last element when non-dir
> -                * redirects become possible
> +                * This dentry should be a regular file if this is
> +                * a metacopy dentry or previous layer lookup found
> +                * a metacopy dentry.
>                  */
> -               WARN_ON(!last_element);
> +               if ((err || d->metacopy) && !d_is_reg(this)) {
> +                       d->stop = true;
> +                       goto put_and_out;
> +               }
> +               d->stop = !err;
> +               d->metacopy = !!err;
>                 goto out;
>         }
> -       if (last_element)
> +       if (last_element) {
> +               if (d->metacopy) {
> +                       d->stop = true;
> +                       goto put_and_out;
> +               }
>                 d->is_dir = true;
> +       }
>         if (d->last)
>                 goto out;
>
> @@ -823,7 +838,7 @@ struct dentry *ovl_lookup(struct inode *
>         struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
>         struct ovl_entry *poe = dentry->d_parent->d_fsdata;
>         struct ovl_entry *roe = dentry->d_sb->s_root->d_fsdata;
> -       struct ovl_path *stack = NULL;
> +       struct ovl_path *stack = NULL, *origin_path = NULL;
>         struct dentry *upperdir, *upperdentry = NULL;
>         struct dentry *origin = NULL;
>         struct dentry *index = NULL;
> @@ -834,6 +849,7 @@ struct dentry *ovl_lookup(struct inode *
>         struct dentry *this;
>         unsigned int i;
>         int err;
> +       bool metacopy = false;
>         struct ovl_lookup_data d = {
>                 .name = dentry->d_name,
>                 .is_dir = false,
> @@ -841,6 +857,7 @@ struct dentry *ovl_lookup(struct inode *
>                 .stop = false,
>                 .last = ofs->config.redirect_follow ? false : !poe->numlower,
>                 .redirect = NULL,
> +               .metacopy = false,
>         };
>
>         if (dentry->d_name.len > ofs->namelen)
> @@ -859,7 +876,8 @@ struct dentry *ovl_lookup(struct inode *
>                         goto out;
>                 }
>                 if (upperdentry && !d.is_dir) {
> -                       BUG_ON(!d.stop || d.redirect);
> +                       unsigned int origin_ctr = 0;
> +                       BUG_ON(d.redirect);
>                         /*
>                          * Lookup copy up origin by decoding origin file handle.
>                          * We may get a disconnected dentry, which is fine,
> @@ -870,9 +888,13 @@ struct dentry *ovl_lookup(struct inode *
>                          * number - it's the same as if we held a reference
>                          * to a dentry in lower layer that was moved under us.
>                          */
> -                       err = ovl_check_origin(ofs, upperdentry, &stack, &ctr);
> +                       err = ovl_check_origin(ofs, upperdentry, &origin_path,
> +                                              &origin_ctr);
>                         if (err)
>                                 goto out_put_upper;
> +
> +                       if (d.metacopy)
> +                               metacopy = true;
>                 }
>
>                 if (d.redirect) {
> @@ -913,7 +935,7 @@ struct dentry *ovl_lookup(struct inode *
>                  * If no origin fh is stored in upper of a merge dir, store fh
>                  * of lower dir and set upper parent "impure".
>                  */
> -               if (upperdentry && !ctr && !ofs->noxattr) {
> +               if (upperdentry && !ctr && !ofs->noxattr && d.is_dir) {
>                         err = ovl_fix_origin(dentry, this, upperdentry);
>                         if (err) {
>                                 dput(this);
> @@ -925,16 +947,39 @@ struct dentry *ovl_lookup(struct inode *
>                  * When "verify_lower" feature is enabled, do not merge with a
>                  * lower dir that does not match a stored origin xattr. In any
>                  * case, only verified origin is used for index lookup.
> +                *
> +                * For non-dir dentry, if index=on, then ensure origin
> +                * matches the dentry found using path based lookup,
> +                * otherwise error out. If index=off, then do not error
> +                * out if origin does not match.
>                  */
> -               if (upperdentry && !ctr && ovl_verify_lower(dentry->d_sb)) {
> +               if (upperdentry && !ctr &&
> +                   ((d.is_dir && ovl_verify_lower(dentry->d_sb)) ||
> +                    (!d.is_dir && origin_path))) {
>                         err = ovl_verify_origin(upperdentry, this, false);
>                         if (err) {
> -                               dput(this);
> -                               break;
> +                               if (d.is_dir) {
> +                                       dput(this);
> +                                       break;
> +                               } else if (ofs->config.index) {
> +                                       dput(this);
> +                                       goto out_put;
> +                               }
> +                       } else {
> +                               /* Bless lower as verified origin */
> +                               origin = this;
>                         }
> +               }
>

Logically, this looks correct, but if we don't need the blessing for index=off
and we won't fail lookup, then there is no need to ovl_verify_origin() at
all if index=off, so this shrinks a few lines of code and saves the extra
check.

Thanks,
Amir.
--
To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux