diff options
-rw-r--r-- | fs/overlayfs/copy_up.c | 12 | ||||
-rw-r--r-- | fs/overlayfs/namei.c | 4 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 6 | ||||
-rw-r--r-- | fs/overlayfs/super.c | 13 |
4 files changed, 27 insertions, 8 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 42807cb57da0..5e8fd99557e1 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -233,7 +233,7 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat) return err; } -struct ovl_fh *ovl_encode_fh(struct dentry *lower) +struct ovl_fh *ovl_encode_fh(struct dentry *lower, bool is_upper) { struct ovl_fh *fh; int fh_type, fh_len, dwords; @@ -272,6 +272,14 @@ struct ovl_fh *ovl_encode_fh(struct dentry *lower) fh->magic = OVL_FH_MAGIC; fh->type = fh_type; fh->flags = OVL_FH_FLAG_CPU_ENDIAN; + /* + * When we will want to decode an overlay dentry from this handle + * and all layers are on the same fs, if we get a disconncted real + * dentry when we decode fid, the only way to tell if we should assign + * it to upperdentry or to lowerstack is by checking this flag. + */ + if (is_upper) + fh->flags |= OVL_FH_FLAG_PATH_UPPER; fh->len = fh_len; fh->uuid = *uuid; memcpy(fh->fid, buf, buflen); @@ -293,7 +301,7 @@ static int ovl_set_origin(struct dentry *dentry, struct dentry *lower, * up and a pure upper inode. */ if (ovl_can_decode_fh(lower->d_sb)) { - fh = ovl_encode_fh(lower); + fh = ovl_encode_fh(lower, false); if (IS_ERR(fh)) return PTR_ERR(fh); } diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index 197b53d34861..0c816e9aa50c 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -350,13 +350,13 @@ static int ovl_verify_origin_fh(struct dentry *dentry, const struct ovl_fh *fh) * Return 0 on match, -ESTALE on mismatch, < 0 on error. */ int ovl_verify_origin(struct dentry *dentry, struct vfsmount *mnt, - struct dentry *origin, bool set) + struct dentry *origin, bool is_upper, bool set) { struct inode *inode; struct ovl_fh *fh; int err; - fh = ovl_encode_fh(origin); + fh = ovl_encode_fh(origin, is_upper); err = PTR_ERR(fh); if (IS_ERR(fh)) goto fail; diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 38ac84cba6ea..58bbd135a7b3 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -42,6 +42,8 @@ enum ovl_flag { /* CPU byte order required for fid decoding: */ #define OVL_FH_FLAG_BIG_ENDIAN (1 << 0) #define OVL_FH_FLAG_ANY_ENDIAN (1 << 1) +/* Is the real inode encoded in fid an upper inode? */ +#define OVL_FH_FLAG_PATH_UPPER (1 << 2) #define OVL_FH_FLAG_ALL (OVL_FH_FLAG_BIG_ENDIAN | OVL_FH_FLAG_ANY_ENDIAN) @@ -233,7 +235,7 @@ static inline bool ovl_is_impuredir(struct dentry *dentry) /* namei.c */ int ovl_verify_origin(struct dentry *dentry, struct vfsmount *mnt, - struct dentry *origin, bool set); + struct dentry *origin, bool is_upper, bool set); int ovl_path_next(int idx, struct dentry *dentry, struct path *path); struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags); bool ovl_lower_positive(struct dentry *dentry); @@ -292,4 +294,4 @@ int ovl_copy_up(struct dentry *dentry); int ovl_copy_up_flags(struct dentry *dentry, int flags); int ovl_copy_xattr(struct dentry *old, struct dentry *new); int ovl_set_attr(struct dentry *upper, struct kstat *stat); -struct ovl_fh *ovl_encode_fh(struct dentry *lower); +struct ovl_fh *ovl_encode_fh(struct dentry *lower, bool is_upper); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index bfdcff0f3168..a313af25dac2 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -1050,7 +1050,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) if (!(ovl_force_readonly(ufs)) && ufs->config.index) { /* Verify lower root is upper root origin */ err = ovl_verify_origin(upperpath.dentry, ufs->lower_mnt[0], - stack[0].dentry, true); + stack[0].dentry, false, true); if (err) { pr_err("overlayfs: failed to verify upper root origin\n"); goto out_put_lower_mnt; @@ -1062,8 +1062,17 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) if (IS_ERR(ufs->indexdir)) goto out_put_lower_mnt; - if (!ufs->indexdir) + if (ufs->indexdir) { + /* Verify upper root is index dir origin */ + err = ovl_verify_origin(ufs->indexdir, ufs->upper_mnt, + upperpath.dentry, true, true); + if (err) + pr_err("overlayfs: failed to verify index dir origin\n"); + } + if (err || !ufs->indexdir) pr_warn("overlayfs: try deleting index dir or mounting with '-o index=off' to disable inodes index.\n"); + if (err) + goto out_put_indexdir; } /* Show index=off/on in /proc/mounts for any of the reasons above */ |