Re: [PATCH v2 03/17] ovl: decode pure upper file handles

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

 



[Added Al Viro]

On Thu, Jan 4, 2018 at 6:20 PM, Amir Goldstein <amir73il@xxxxxxxxx> wrote:
> Decoding an upper file handle is done by decoding the upper dentry from
> underlying upper fs, finding or allocating an overlay inode that is
> hashed by the real upper inode and instantiating an overlay dentry with
> that inode.
>
> Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
> ---
>  fs/overlayfs/export.c    | 91 ++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/overlayfs/namei.c     |  4 +--
>  fs/overlayfs/overlayfs.h |  2 ++
>  3 files changed, 95 insertions(+), 2 deletions(-)
>
> diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
> index 58c4f5e8a67e..5c72784a0b4d 100644
> --- a/fs/overlayfs/export.c
> +++ b/fs/overlayfs/export.c
> @@ -93,6 +93,97 @@ static int ovl_encode_inode_fh(struct inode *inode, u32 *fid, int *max_len,
>         return type;
>  }
>
> +/*
> + * Find or instantiate an overlay dentry from real dentries.
> + */
> +static struct dentry *ovl_obtain_alias(struct super_block *sb,
> +                                      struct dentry *upper,
> +                                      struct ovl_path *lowerpath)
> +{
> +       struct inode *inode;
> +       struct dentry *dentry;
> +       struct ovl_entry *oe;
> +
> +       /* TODO: obtain non pure-upper */
> +       if (lowerpath)
> +               return ERR_PTR(-EIO);
> +
> +       inode = ovl_get_inode(sb, dget(upper), NULL, NULL, 0);
> +       if (IS_ERR(inode)) {
> +               dput(upper);
> +               return ERR_CAST(inode);
> +       }
> +
> +       dentry = d_obtain_alias(inode);
> +       if (IS_ERR(dentry) || dentry->d_fsdata)

Racing two instances of this code, each thinking it got a new alias
and trying to fill it, results in a memory leak.

Haven't checked in too much depth, but apparently other filesystems
are not affected, so we need something special here.

One solution: split d_instantiate_anon(dentry, inode) out of
__d_obtain_alias() and supply that with the already initialized
dentry.

Al?

Thanks,
Miklos

> +               return dentry;
> +
> +       oe = ovl_alloc_entry(0);
> +       if (!oe) {
> +               dput(dentry);
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       dentry->d_fsdata = oe;
> +       ovl_dentry_set_upper_alias(dentry);
> +
> +       return dentry;
> +}
> +
> +static struct dentry *ovl_upper_fh_to_d(struct super_block *sb,
> +                                       struct ovl_fh *fh)
> +{
> +       struct ovl_fs *ofs = sb->s_fs_info;
> +       struct dentry *dentry;
> +       struct dentry *upper;
> +
> +       if (!ofs->upper_mnt)
> +               return ERR_PTR(-EACCES);
> +
> +       upper = ovl_decode_fh(fh, ofs->upper_mnt);
> +       if (IS_ERR_OR_NULL(upper))
> +               return upper;
> +
> +       dentry = ovl_obtain_alias(sb, upper, NULL);
> +       dput(upper);
> +
> +       return dentry;
> +}
> +
> +static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid,
> +                                      int fh_len, int fh_type)
> +{
> +       struct dentry *dentry = NULL;
> +       struct ovl_fh *fh = (struct ovl_fh *) fid;
> +       int len = fh_len << 2;
> +       unsigned int flags = 0;
> +       int err;
> +
> +       err = -EINVAL;
> +       if (fh_type != OVL_FILEID)
> +               goto out_err;
> +
> +       err = ovl_check_fh_len(fh, len);
> +       if (err)
> +               goto out_err;
> +
> +       /* TODO: decode non-upper */
> +       flags = fh->flags;
> +       if (flags & OVL_FH_FLAG_PATH_UPPER)
> +               dentry = ovl_upper_fh_to_d(sb, fh);
> +       err = PTR_ERR(dentry);
> +       if (IS_ERR(dentry) && err != -ESTALE)
> +               goto out_err;
> +
> +       return dentry;
> +
> +out_err:
> +       pr_warn_ratelimited("overlayfs: failed to decode file handle (len=%d, type=%d, flags=%x, err=%i)\n",
> +                           len, fh_type, flags, err);
> +       return ERR_PTR(err);
> +}
> +
>  const struct export_operations ovl_export_operations = {
>         .encode_fh      = ovl_encode_inode_fh,
> +       .fh_to_dentry   = ovl_fh_to_dentry,
>  };
> diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
> index a69cedf06000..87d39384dc55 100644
> --- a/fs/overlayfs/namei.c
> +++ b/fs/overlayfs/namei.c
> @@ -107,7 +107,7 @@ static int ovl_acceptable(void *ctx, struct dentry *dentry)
>   * Return -ENODATA for "origin unknown".
>   * Return <0 for an invalid file handle.
>   */
> -static int ovl_check_fh_len(struct ovl_fh *fh, int fh_len)
> +int ovl_check_fh_len(struct ovl_fh *fh, int fh_len)
>  {
>         if (fh_len < sizeof(struct ovl_fh) || fh_len < fh->len)
>                 return -EINVAL;
> @@ -171,7 +171,7 @@ static struct ovl_fh *ovl_get_origin_fh(struct dentry *dentry)
>         goto out;
>  }
>
> -static struct dentry *ovl_decode_fh(struct ovl_fh *fh, struct vfsmount *mnt)
> +struct dentry *ovl_decode_fh(struct ovl_fh *fh, struct vfsmount *mnt)
>  {
>         struct dentry *origin;
>         int bytes;
> diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
> index f6fd999cb98e..c4f8e98e209e 100644
> --- a/fs/overlayfs/overlayfs.h
> +++ b/fs/overlayfs/overlayfs.h
> @@ -258,6 +258,8 @@ static inline bool ovl_is_impuredir(struct dentry *dentry)
>
>
>  /* namei.c */
> +int ovl_check_fh_len(struct ovl_fh *fh, int fh_len);
> +struct dentry *ovl_decode_fh(struct ovl_fh *fh, struct vfsmount *mnt);
>  int ovl_verify_origin(struct dentry *dentry, struct dentry *origin,
>                       bool is_upper, bool set);
>  int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index);
> --
> 2.7.4
>



[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux