On Tue, Oct 17, 2017 at 7:00 PM, Amir Goldstein <amir73il@xxxxxxxxx> wrote: > Directory index entries should have origin xattr pointing to the > real upper dir. Non-dir index entries are hardlinks to the upper > real inode. For non-dir index, we can read the copy up origin xattr > directly from the index dentry, but for dir index we first need to > decode the upper directory. > > Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> > --- > fs/overlayfs/namei.c | 60 +++++++++++++++++++++++++++++++++--------------- > fs/overlayfs/overlayfs.h | 4 ++-- > fs/overlayfs/readdir.c | 2 +- > 3 files changed, 45 insertions(+), 21 deletions(-) > > diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c > index 1afc6d6e99b9..aba57d31d850 100644 > --- a/fs/overlayfs/namei.c > +++ b/fs/overlayfs/namei.c > @@ -391,36 +391,45 @@ int ovl_verify_origin(struct dentry *dentry, struct dentry *origin, > goto out; > } > > +/* Get upper dentry from index */ > +struct dentry *ovl_index_upper(struct dentry *index, struct vfsmount *mnt) > +{ > + struct path upperpath = { .mnt = mnt }; > + struct path *stack = &upperpath; > + unsigned int ctr = 0; > + int err; > + > + if (!d_is_dir(index)) > + return dget(index); > + > + err = ovl_check_origin(index, stack, 1, &stack, &ctr); > + if (!err && !ctr) > + err = -ENODATA; > + if (err) > + return ERR_PTR(err); > + > + return upperpath.dentry; > +} > + > /* > * Verify that an index entry name matches the origin file handle stored in > * OVL_XATTR_ORIGIN and that origin file handle can be decoded to lower path. > * Return 0 on match, -ESTALE on mismatch or stale origin, < 0 on error. > */ > -int ovl_verify_index(struct dentry *index, struct path *lowerstack, > - unsigned int numlower) > +int ovl_verify_index(struct dentry *index, struct vfsmount *mnt, > + struct path *lowerstack, unsigned int numlower) > { > struct ovl_fh *fh = NULL; > size_t len; > struct path origin = { }; > struct path *stack = &origin; > unsigned int ctr = 0; > + struct dentry *upper = NULL; > int err; > > if (!d_inode(index)) > return 0; > > - /* > - * Directory index entries are going to be used for looking up > - * redirected upper dirs by lower dir fh when decoding an overlay > - * file handle of a merge dir. We don't know the verification rules > - * for directory index entries, because they have not been implemented > - * yet, so return EROFS if those entries are found to avoid corrupting > - * an index that was created by a newer kernel. > - */ > - err = -EROFS; > - if (d_is_dir(index)) > - goto fail; > - > err = -EINVAL; > if (index->d_name.len < sizeof(struct ovl_fh)*2) > goto fail; > @@ -446,23 +455,38 @@ int ovl_verify_index(struct dentry *index, struct path *lowerstack, > if (ovl_is_whiteout(index)) > goto out; > > - err = ovl_verify_origin_fh(index, fh); > + /* > + * Directory index entries should have origin xattr pointing to the > + * real upper dir. Non-dir index entries are hardlinks to the upper > + * real inode. For non-dir index, we can read the copy up origin xattr > + * directly from the index dentry, but for dir index we first need to > + * decode the upper directory. > + */ > + upper = ovl_index_upper(index, mnt); > + if (IS_ERR(upper)) { > + err = PTR_ERR(upper); > + if (err) > + goto fail; > + } > + > + err = ovl_verify_origin_fh(upper, fh); FYI, dput(upper) here instead of out: pushed fixup patch to ovl-nfs-export-wip-v1 > if (err) > goto fail; > > - err = ovl_check_origin(index, lowerstack, numlower, &stack, &ctr); > + err = ovl_check_origin(upper, lowerstack, numlower, &stack, &ctr); > if (!err && !ctr) > err = -ESTALE; > if (err) > goto fail; > > /* Check if index is orphan and don't warn before cleaning it */ > - if (d_inode(index)->i_nlink == 1 && > + if (!d_is_dir(index) && d_inode(index)->i_nlink == 1 && > ovl_get_nlink(index, origin.dentry, 0) == 0) > err = -ENOENT; > > - dput(origin.dentry); > out: > + dput(origin.dentry); > + dput(upper); > kfree(fh); > return err; > > diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h > index 35f5452e61e0..e4caad7bae19 100644 > --- a/fs/overlayfs/overlayfs.h > +++ b/fs/overlayfs/overlayfs.h > @@ -263,8 +263,8 @@ static inline bool ovl_is_impuredir(struct dentry *dentry) > /* namei.c */ > int ovl_verify_origin(struct dentry *dentry, struct dentry *origin, > bool is_upper, bool set); > -int ovl_verify_index(struct dentry *index, struct path *lowerstack, > - unsigned int numlower); > +int ovl_verify_index(struct dentry *index, struct vfsmount *mnt, > + struct path *lowerstack, unsigned int numlower); > int ovl_get_index_name(struct dentry *origin, struct qstr *name); > int ovl_path_next(int idx, struct dentry *dentry, struct path *path, int *idxp); > struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags); > diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c > index ba44546ad1ed..479ce47ba411 100644 > --- a/fs/overlayfs/readdir.c > +++ b/fs/overlayfs/readdir.c > @@ -1055,7 +1055,7 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt, > index = NULL; > break; > } > - err = ovl_verify_index(index, lowerstack, numlower); > + err = ovl_verify_index(index, mnt, lowerstack, numlower); > if (err) { > if (err == -EROFS) > break; > -- > 2.7.4 > -- 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