Commit 54fb347e authored by Amir Goldstein's avatar Amir Goldstein Committed by Miklos Szeredi

ovl: verify index dir matches upper dir

An index dir contains persistent hardlinks to files in upper dir.
Therefore, we must never mount an existing index dir with a differnt
upper dir.

Store the upper root dir file handle in index dir inode when index
dir is created and verify the file handle before using an existing
index dir on mount.

Add an 'is_upper' flag to the overlay file handle encoding and set it
when encoding the upper root file handle. This is not critical for index
dir verification, but it is good practice towards a standard overlayfs
file handle format for NFS export.
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 8b88a2e6
...@@ -233,7 +233,7 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat) ...@@ -233,7 +233,7 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat)
return err; 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; struct ovl_fh *fh;
int fh_type, fh_len, dwords; int fh_type, fh_len, dwords;
...@@ -272,6 +272,14 @@ struct ovl_fh *ovl_encode_fh(struct dentry *lower) ...@@ -272,6 +272,14 @@ struct ovl_fh *ovl_encode_fh(struct dentry *lower)
fh->magic = OVL_FH_MAGIC; fh->magic = OVL_FH_MAGIC;
fh->type = fh_type; fh->type = fh_type;
fh->flags = OVL_FH_FLAG_CPU_ENDIAN; 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->len = fh_len;
fh->uuid = *uuid; fh->uuid = *uuid;
memcpy(fh->fid, buf, buflen); memcpy(fh->fid, buf, buflen);
...@@ -293,7 +301,7 @@ static int ovl_set_origin(struct dentry *dentry, struct dentry *lower, ...@@ -293,7 +301,7 @@ static int ovl_set_origin(struct dentry *dentry, struct dentry *lower,
* up and a pure upper inode. * up and a pure upper inode.
*/ */
if (ovl_can_decode_fh(lower->d_sb)) { if (ovl_can_decode_fh(lower->d_sb)) {
fh = ovl_encode_fh(lower); fh = ovl_encode_fh(lower, false);
if (IS_ERR(fh)) if (IS_ERR(fh))
return PTR_ERR(fh); return PTR_ERR(fh);
} }
......
...@@ -350,13 +350,13 @@ static int ovl_verify_origin_fh(struct dentry *dentry, const struct ovl_fh *fh) ...@@ -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. * Return 0 on match, -ESTALE on mismatch, < 0 on error.
*/ */
int ovl_verify_origin(struct dentry *dentry, struct vfsmount *mnt, 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 inode *inode;
struct ovl_fh *fh; struct ovl_fh *fh;
int err; int err;
fh = ovl_encode_fh(origin); fh = ovl_encode_fh(origin, is_upper);
err = PTR_ERR(fh); err = PTR_ERR(fh);
if (IS_ERR(fh)) if (IS_ERR(fh))
goto fail; goto fail;
......
...@@ -42,6 +42,8 @@ enum ovl_flag { ...@@ -42,6 +42,8 @@ enum ovl_flag {
/* CPU byte order required for fid decoding: */ /* CPU byte order required for fid decoding: */
#define OVL_FH_FLAG_BIG_ENDIAN (1 << 0) #define OVL_FH_FLAG_BIG_ENDIAN (1 << 0)
#define OVL_FH_FLAG_ANY_ENDIAN (1 << 1) #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) #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) ...@@ -233,7 +235,7 @@ static inline bool ovl_is_impuredir(struct dentry *dentry)
/* namei.c */ /* namei.c */
int ovl_verify_origin(struct dentry *dentry, struct vfsmount *mnt, 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); 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); struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags);
bool ovl_lower_positive(struct dentry *dentry); bool ovl_lower_positive(struct dentry *dentry);
...@@ -292,4 +294,4 @@ int ovl_copy_up(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_up_flags(struct dentry *dentry, int flags);
int ovl_copy_xattr(struct dentry *old, struct dentry *new); int ovl_copy_xattr(struct dentry *old, struct dentry *new);
int ovl_set_attr(struct dentry *upper, struct kstat *stat); 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);
...@@ -1050,7 +1050,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -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) { if (!(ovl_force_readonly(ufs)) && ufs->config.index) {
/* Verify lower root is upper root origin */ /* Verify lower root is upper root origin */
err = ovl_verify_origin(upperpath.dentry, ufs->lower_mnt[0], err = ovl_verify_origin(upperpath.dentry, ufs->lower_mnt[0],
stack[0].dentry, true); stack[0].dentry, false, true);
if (err) { if (err) {
pr_err("overlayfs: failed to verify upper root origin\n"); pr_err("overlayfs: failed to verify upper root origin\n");
goto out_put_lower_mnt; goto out_put_lower_mnt;
...@@ -1062,8 +1062,17 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1062,8 +1062,17 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
if (IS_ERR(ufs->indexdir)) if (IS_ERR(ufs->indexdir))
goto out_put_lower_mnt; 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"); 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 */ /* Show index=off/on in /proc/mounts for any of the reasons above */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment