From: Amir Goldstein <amir73il@gmail.com>
To: Miklos Szeredi <miklos@szeredi.hu>
Cc: Vivek Goyal <vgoyal@redhat.com>,
Al Viro <viro@zeniv.linux.org.uk>,
linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org
Subject: [PATCH v4 15/15] ovl: add support for verify_lower option
Date: Mon, 1 May 2017 16:42:06 +0300 [thread overview]
Message-ID: <1493646126-10101-16-git-send-email-amir73il@gmail.com> (raw)
In-Reply-To: <1493646126-10101-1-git-send-email-amir73il@gmail.com>
When overlayfs is mounted with option 'verify_lower', a directory inode
found in lower layer by name or by redirect_dir is verified against the
file handle of the copy up origin that is stored in the upper layer.
The 'verify_lower' option should not be used after copying layers,
because the new lower directory inodes would fail verification.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/overlayfs/copy_up.c | 2 +-
fs/overlayfs/namei.c | 71 +++++++++++++++++++++++++++++++++++++++++++-----
fs/overlayfs/overlayfs.h | 2 ++
fs/overlayfs/ovl_entry.h | 1 +
fs/overlayfs/super.c | 23 ++++++++++++++++
fs/overlayfs/util.c | 7 +++++
6 files changed, 98 insertions(+), 8 deletions(-)
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 767ae77..0aa626a 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -234,7 +234,7 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat)
return err;
}
-static struct ovl_fh *ovl_encode_fh(struct dentry *lower)
+struct ovl_fh *ovl_encode_fh(struct dentry *lower)
{
struct ovl_fh *fh;
int fh_type, fh_len, dwords;
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 2be2917..4580ac0 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -27,7 +27,8 @@ struct ovl_lookup_data {
bool by_path; /* redirect by path: */
char *redirect; /* - path to follow */
bool by_fh; /* redirect by file handle: */
- struct ovl_fh *fh; /* - file handle to follow */
+ bool verify_fh; /* verify by file handle: */
+ struct ovl_fh *fh; /* - file handle to follow/verify */
};
static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d,
@@ -206,14 +207,14 @@ static int ovl_lookup_data(struct dentry *this, struct ovl_lookup_data *d,
}
/*
* If non-dir has a valid origin file handle, it will be used to
- * find the copy up origin in lower layers.
- *
- * Directory lookup by fh is not desired for all workloads, so it
- * will be enabled by a future mount option.
+ * find the copy up origin in lower layers. If verify_lower is
+ * enabled a directory origin file handle will be used to verify
+ * lower directory that was found by path.
*/
- if (d->by_fh && !d_is_dir(this)) {
+ if (d->by_fh && (d->verify_fh || !d_is_dir(this))) {
ovl_check_redirect_fh(this, d);
- d->stop = !d->fh;
+ if (!d_is_dir(this) && !d->fh)
+ d->stop = true;
}
out:
@@ -364,6 +365,57 @@ static int ovl_find_layer_by_fh(struct dentry *dentry, int idx,
}
/*
+ * Verify that a lower directory matches the stored file handle.
+ * Return 0 on match, > 0 on mismatch, < 0 on error.
+ */
+static int ovl_verify_lower_fh(struct dentry **lower,
+ struct ovl_lookup_data *d)
+{
+ struct ovl_fh *fh;
+ struct inode *inode;
+ int ret;
+
+ /* We should be called only to verify lower dir matches fh */
+ if (WARN_ON(!d->fh) || !S_ISDIR(d->mode))
+ return -EIO;
+
+ /* We currently support verify_lower for single lower layer */
+ if (WARN_ON(!d->last))
+ return -EIO;
+
+ /* If we have a copy up origin, we should have found a lower dir */
+ if (!*lower) {
+ pr_warn_ratelimited("overlayfs: failed to find lower dir\n");
+ return -ENOENT;
+ }
+
+ fh = ovl_encode_fh(*lower);
+ if (IS_ERR(fh)) {
+ ret = PTR_ERR(fh);
+ fh = NULL;
+ goto fail;
+ } else if (fh->len != d->fh->len || memcmp(fh, d->fh, fh->len)) {
+ ret = fh->len;
+ goto fail;
+ }
+
+ ret = 0;
+out:
+ /* Don't verify that handle again */
+ ovl_reset_redirect_fh(d);
+ kfree(fh);
+ return ret;
+
+fail:
+ inode = d_inode(*lower);
+ pr_warn_ratelimited("overlayfs: failed to verify lower dir (ino=%lu, ret=%i) - were layers copied?\n",
+ inode ? inode->i_ino : 0, ret);
+ dput(*lower);
+ *lower = NULL;
+ goto out;
+}
+
+/*
* Returns next layer in stack starting from top.
* Returns -1 if this is the last layer.
*/
@@ -411,6 +463,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
.by_path = true,
.redirect = NULL,
.by_fh = ofs->redirect_fh,
+ .verify_fh = ofs->config.verify_lower,
.fh = NULL,
};
@@ -484,6 +537,10 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
if (err)
goto out_put;
+ /* Verify that lower matches the copy up origin fh */
+ if (d.verify_fh && d.fh && ovl_verify_lower_fh(&this, &d))
+ break;
+
if (!this)
continue;
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 90181e16..d9ff028a 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -190,6 +190,7 @@ bool ovl_dentry_is_whiteout(struct dentry *dentry);
void ovl_dentry_set_opaque(struct dentry *dentry);
bool ovl_redirect_dir(struct super_block *sb);
void ovl_clear_redirect_dir(struct super_block *sb);
+bool ovl_verify_lower(struct super_block *sb);
const char *ovl_dentry_get_redirect(struct dentry *dentry);
void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect);
bool ovl_redirect_fh(struct super_block *sb);
@@ -263,3 +264,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);
diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
index 3abf025..0e26af2 100644
--- a/fs/overlayfs/ovl_entry.h
+++ b/fs/overlayfs/ovl_entry.h
@@ -14,6 +14,7 @@ struct ovl_config {
char *workdir;
bool default_permissions;
bool redirect_dir;
+ bool verify_lower;
};
/* private information held for overlayfs's superblock */
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index e639750..a7c03ca 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -280,6 +280,7 @@ enum {
OPT_DEFAULT_PERMISSIONS,
OPT_REDIRECT_DIR_ON,
OPT_REDIRECT_DIR_OFF,
+ OPT_VERIFY_LOWER,
OPT_ERR,
};
@@ -290,6 +291,7 @@ static const match_table_t ovl_tokens = {
{OPT_DEFAULT_PERMISSIONS, "default_permissions"},
{OPT_REDIRECT_DIR_ON, "redirect_dir=on"},
{OPT_REDIRECT_DIR_OFF, "redirect_dir=off"},
+ {OPT_VERIFY_LOWER, "verify_lower"},
{OPT_ERR, NULL}
};
@@ -362,6 +364,10 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
config->redirect_dir = false;
break;
+ case OPT_VERIFY_LOWER:
+ config->verify_lower = true;
+ break;
+
default:
pr_err("overlayfs: unrecognized mount option \"%s\" or missing value\n", p);
return -EINVAL;
@@ -957,6 +963,23 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
pr_warn("overlayfs: lower fs needs to report s_uuid.\n");
}
+ /*
+ * The verify_lower feature is used to verify that lower directory
+ * found by path matches the stored copy up origin. Currently, only
+ * single lower layer on same fs as upper layer is supported.
+ */
+ if (ufs->config.verify_lower) {
+ ufs->config.verify_lower = false;
+ if (!ufs->same_sb)
+ pr_warn("overlayfs: option \"verify_lower\" requires lower/upper on same fs.\n");
+ if (numlower > 1)
+ pr_warn("overlayfs: option \"verify_lower\" requires single lower layer.\n");
+ else if (!ufs->redirect_fh)
+ pr_warn("overlayfs: option \"verify_lower\" not supported by lower fs.\n");
+ else
+ ufs->config.verify_lower = true;
+ }
+
if (remote)
sb->s_d_op = &ovl_reval_dentry_operations;
else
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 08c55e6..dad924d 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -207,6 +207,13 @@ void ovl_clear_redirect_dir(struct super_block *sb)
ofs->config.redirect_dir = false;
}
+bool ovl_verify_lower(struct super_block *sb)
+{
+ struct ovl_fs *ofs = sb->s_fs_info;
+
+ return ofs->config.verify_lower;
+}
+
const char *ovl_dentry_get_redirect(struct dentry *dentry)
{
struct ovl_entry *oe = dentry->d_fsdata;
--
2.7.4
next prev parent reply other threads:[~2017-05-01 13:42 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-05-01 13:41 [PATCH v4 00/15] overlayfs constant inode numbers Amir Goldstein
2017-05-01 13:41 ` [PATCH v4 01/15] ovl: check if all layers are on the same fs Amir Goldstein
2017-05-01 13:41 ` [PATCH v4 02/15] ovl: store file handle of lower inode on copy up Amir Goldstein
2017-05-03 15:14 ` Amir Goldstein
2017-05-03 15:32 ` Amir Goldstein
2017-05-01 13:41 ` [PATCH v4 03/15] ovl: use an auxiliary var for overlay root entry Amir Goldstein
2017-05-01 13:41 ` [PATCH v4 04/15] ovl: factor out ovl_lookup_data() Amir Goldstein
2017-05-01 13:41 ` [PATCH v4 05/15] ovl: store the file type in ovl_lookup_data Amir Goldstein
2017-05-01 13:41 ` [PATCH v4 06/15] ovl: pass the stack index on ovl_lookup_data Amir Goldstein
2017-05-01 13:41 ` [PATCH v4 07/15] ovl: lookup copy up origin of non-dir inode Amir Goldstein
2017-05-01 13:41 ` [PATCH v4 08/15] ovl: lookup non-dir copy up origin by file handle Amir Goldstein
2017-05-01 13:42 ` [PATCH v4 09/15] ovl: validate lower layer uuid on redirect by fh Amir Goldstein
2017-05-01 13:42 ` [PATCH v4 10/15] ovl: constant st_ino/st_dev across copy up Amir Goldstein
2017-05-01 13:42 ` [PATCH v4 11/15] ovl: persistent inode number for directories Amir Goldstein
2017-05-01 13:42 ` [PATCH v4 12/15] ovl: fix du --one-file-system on overlay mount Amir Goldstein
2017-05-01 13:42 ` [PATCH v4 13/15] ovl: persistent inode numbers for upper hardlinks Amir Goldstein
2017-05-01 13:42 ` [PATCH v4 14/15] ovl: update documentation w.r.t. constant inode numbers Amir Goldstein
2017-05-01 13:42 ` Amir Goldstein [this message]
2017-05-03 15:43 ` [PATCH v4 00/15] overlayfs " Miklos Szeredi
2017-05-03 15:46 ` Amir Goldstein
2017-05-03 20:01 ` Amir Goldstein
2017-05-04 8:24 ` Miklos Szeredi
2017-05-04 9:15 ` Miklos Szeredi
2017-05-04 10:18 ` Amir Goldstein
2017-05-04 11:59 ` Amir Goldstein
2017-05-04 12:10 ` Miklos Szeredi
2017-05-04 14:14 ` Amir Goldstein
2017-05-04 21:03 ` Miklos Szeredi
2017-05-05 7:25 ` Amir Goldstein
2017-05-05 7:55 ` Amir Goldstein
2017-05-05 9:53 ` Miklos Szeredi
2017-05-05 9:58 ` Amir Goldstein
2017-05-10 8:58 ` Amir Goldstein
2017-05-10 9:21 ` Miklos Szeredi
2017-05-10 10:09 ` Amir Goldstein
2017-05-10 16:00 ` Amir Goldstein
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1493646126-10101-16-git-send-email-amir73il@gmail.com \
--to=amir73il@gmail.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-unionfs@vger.kernel.org \
--cc=miklos@szeredi.hu \
--cc=vgoyal@redhat.com \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).