Message ID | c92a93fae2484e554b0d8cce5d02b8b4d6758c67.1683102959.git.alexl@redhat.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | ovl: Add support for fs-verity checking of lowerdata | expand |
On Wed, May 3, 2023 at 11:52 AM Alexander Larsson <alexl@redhat.com> wrote: > > During regular metacopy, if lowerdata file has fs-verity enabled, > set the new overlay.verity xattr (if enabled). > > During real data copy up, remove any old overlay.verity xattr. > > If verity is required, and lowerdata does not have fs-verity enabled, > fall back to full copy-up (or the generated metacopy would not validate). > > Signed-off-by: Alexander Larsson <alexl@redhat.com> Looks fine to me Reviewed-by: Amir Goldstein <amir73il@gmail.com> > --- > fs/overlayfs/copy_up.c | 31 +++++++++++++++++++++++++++++++ > fs/overlayfs/overlayfs.h | 3 +++ > fs/overlayfs/util.c | 39 ++++++++++++++++++++++++++++++++++++++- > 3 files changed, 72 insertions(+), 1 deletion(-) > > diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c > index eb266fb68730..e25bdc2baef3 100644 > --- a/fs/overlayfs/copy_up.c > +++ b/fs/overlayfs/copy_up.c > @@ -19,6 +19,7 @@ > #include <linux/fdtable.h> > #include <linux/ratelimit.h> > #include <linux/exportfs.h> > +#include <linux/fsverity.h> > #include "overlayfs.h" > > #define OVL_COPY_UP_CHUNK_SIZE (1 << 20) > @@ -644,6 +645,18 @@ static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp) > if (c->metacopy) { > err = ovl_check_setxattr(ofs, temp, OVL_XATTR_METACOPY, > NULL, 0, -EOPNOTSUPP); > + > + /* Copy the verity digest if any so we can validate the copy-up later */ > + if (!err) { > + struct path lowerdatapath; > + > + ovl_path_lowerdata(c->dentry, &lowerdatapath); > + if (WARN_ON_ONCE(lowerdatapath.dentry == NULL)) > + err = -EIO; > + else > + err = ovl_set_verity_xattr_from(ofs, temp, &lowerdatapath); > + } > + > if (err) > return err; > } > @@ -919,6 +932,19 @@ static bool ovl_need_meta_copy_up(struct dentry *dentry, umode_t mode, > if (flags && ((OPEN_FMODE(flags) & FMODE_WRITE) || (flags & O_TRUNC))) > return false; > > + /* Fall back to full copy if no fsverity on source data and we require verity */ > + if (ofs->config.require_verity) { > + struct path lowerdata; > + > + ovl_path_lowerdata(dentry, &lowerdata); > + > + if (WARN_ON_ONCE(lowerdata.dentry == NULL) || > + ovl_ensure_verity_loaded(&lowerdata) || > + !fsverity_get_info(d_inode(lowerdata.dentry))) { > + return false; > + } > + } > + > return true; > } > > @@ -985,6 +1011,11 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) > if (err) > goto out_free; > > + err = ovl_removexattr(ofs, upperpath.dentry, OVL_XATTR_VERITY); > + if (err && err != -ENODATA) > + goto out_free; > + > + err = 0; > ovl_set_upperdata(d_inode(c->dentry)); > out_free: > kfree(capability); > diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h > index 07475eaae2ca..1cc3c8df3a4d 100644 > --- a/fs/overlayfs/overlayfs.h > +++ b/fs/overlayfs/overlayfs.h > @@ -464,11 +464,14 @@ int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir); > int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path); > bool ovl_is_metacopy_dentry(struct dentry *dentry); > char *ovl_get_redirect_xattr(struct ovl_fs *ofs, const struct path *path, int padding); > +int ovl_ensure_verity_loaded(struct path *path); > int ovl_get_verity_xattr(struct ovl_fs *ofs, const struct path *path, > u8 *digest_buf, int *buf_length); > int ovl_validate_verity(struct ovl_fs *ofs, > struct path *metapath, > struct path *datapath); > +int ovl_set_verity_xattr_from(struct ovl_fs *ofs, struct dentry *dst, > + struct path *src); > int ovl_sync_status(struct ovl_fs *ofs); > > static inline void ovl_set_flag(unsigned long flag, struct inode *inode) > diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c > index ee296614bd73..733871775b80 100644 > --- a/fs/overlayfs/util.c > +++ b/fs/overlayfs/util.c > @@ -1188,7 +1188,7 @@ int ovl_get_verity_xattr(struct ovl_fs *ofs, const struct path *path, > } > > /* Call with mounter creds as it may open the file */ > -static int ovl_ensure_verity_loaded(struct path *datapath) > +int ovl_ensure_verity_loaded(struct path *datapath) > { > struct inode *inode = d_inode(datapath->dentry); > const struct fsverity_info *vi; > @@ -1262,6 +1262,43 @@ int ovl_validate_verity(struct ovl_fs *ofs, > return 0; > } > > +int ovl_set_verity_xattr_from(struct ovl_fs *ofs, struct dentry *dst, > + struct path *src) > +{ > + int err; > + u8 src_digest[1+FS_VERITY_MAX_DIGEST_SIZE]; > + enum hash_algo verity_algo; > + > + if (!ofs->config.verity || !S_ISREG(d_inode(dst)->i_mode)) > + return 0; > + > + err = -EIO; > + if (src) { > + err = ovl_ensure_verity_loaded(src); > + if (err < 0) { > + pr_warn_ratelimited("lower file '%pd' failed to load fs-verity info\n", > + src->dentry); > + return -EIO; > + } > + > + err = fsverity_get_digest(d_inode(src->dentry), src_digest + 1, &verity_algo); > + } > + if (err == -ENODATA) { > + if (ofs->config.require_verity) { > + pr_warn_ratelimited("lower file '%pd' has no fs-verity digest\n", > + src->dentry); > + return -EIO; > + } > + return 0; > + } > + if (err < 0) > + return err; > + > + src_digest[0] = (u8)verity_algo; > + return ovl_check_setxattr(ofs, dst, OVL_XATTR_VERITY, > + src_digest, 1 + hash_digest_size[verity_algo], -EOPNOTSUPP); > +} > + > /* > * ovl_sync_status() - Check fs sync status for volatile mounts > * > -- > 2.39.2 >
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index eb266fb68730..e25bdc2baef3 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -19,6 +19,7 @@ #include <linux/fdtable.h> #include <linux/ratelimit.h> #include <linux/exportfs.h> +#include <linux/fsverity.h> #include "overlayfs.h" #define OVL_COPY_UP_CHUNK_SIZE (1 << 20) @@ -644,6 +645,18 @@ static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp) if (c->metacopy) { err = ovl_check_setxattr(ofs, temp, OVL_XATTR_METACOPY, NULL, 0, -EOPNOTSUPP); + + /* Copy the verity digest if any so we can validate the copy-up later */ + if (!err) { + struct path lowerdatapath; + + ovl_path_lowerdata(c->dentry, &lowerdatapath); + if (WARN_ON_ONCE(lowerdatapath.dentry == NULL)) + err = -EIO; + else + err = ovl_set_verity_xattr_from(ofs, temp, &lowerdatapath); + } + if (err) return err; } @@ -919,6 +932,19 @@ static bool ovl_need_meta_copy_up(struct dentry *dentry, umode_t mode, if (flags && ((OPEN_FMODE(flags) & FMODE_WRITE) || (flags & O_TRUNC))) return false; + /* Fall back to full copy if no fsverity on source data and we require verity */ + if (ofs->config.require_verity) { + struct path lowerdata; + + ovl_path_lowerdata(dentry, &lowerdata); + + if (WARN_ON_ONCE(lowerdata.dentry == NULL) || + ovl_ensure_verity_loaded(&lowerdata) || + !fsverity_get_info(d_inode(lowerdata.dentry))) { + return false; + } + } + return true; } @@ -985,6 +1011,11 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) if (err) goto out_free; + err = ovl_removexattr(ofs, upperpath.dentry, OVL_XATTR_VERITY); + if (err && err != -ENODATA) + goto out_free; + + err = 0; ovl_set_upperdata(d_inode(c->dentry)); out_free: kfree(capability); diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 07475eaae2ca..1cc3c8df3a4d 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -464,11 +464,14 @@ int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir); int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path); bool ovl_is_metacopy_dentry(struct dentry *dentry); char *ovl_get_redirect_xattr(struct ovl_fs *ofs, const struct path *path, int padding); +int ovl_ensure_verity_loaded(struct path *path); int ovl_get_verity_xattr(struct ovl_fs *ofs, const struct path *path, u8 *digest_buf, int *buf_length); int ovl_validate_verity(struct ovl_fs *ofs, struct path *metapath, struct path *datapath); +int ovl_set_verity_xattr_from(struct ovl_fs *ofs, struct dentry *dst, + struct path *src); int ovl_sync_status(struct ovl_fs *ofs); static inline void ovl_set_flag(unsigned long flag, struct inode *inode) diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index ee296614bd73..733871775b80 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -1188,7 +1188,7 @@ int ovl_get_verity_xattr(struct ovl_fs *ofs, const struct path *path, } /* Call with mounter creds as it may open the file */ -static int ovl_ensure_verity_loaded(struct path *datapath) +int ovl_ensure_verity_loaded(struct path *datapath) { struct inode *inode = d_inode(datapath->dentry); const struct fsverity_info *vi; @@ -1262,6 +1262,43 @@ int ovl_validate_verity(struct ovl_fs *ofs, return 0; } +int ovl_set_verity_xattr_from(struct ovl_fs *ofs, struct dentry *dst, + struct path *src) +{ + int err; + u8 src_digest[1+FS_VERITY_MAX_DIGEST_SIZE]; + enum hash_algo verity_algo; + + if (!ofs->config.verity || !S_ISREG(d_inode(dst)->i_mode)) + return 0; + + err = -EIO; + if (src) { + err = ovl_ensure_verity_loaded(src); + if (err < 0) { + pr_warn_ratelimited("lower file '%pd' failed to load fs-verity info\n", + src->dentry); + return -EIO; + } + + err = fsverity_get_digest(d_inode(src->dentry), src_digest + 1, &verity_algo); + } + if (err == -ENODATA) { + if (ofs->config.require_verity) { + pr_warn_ratelimited("lower file '%pd' has no fs-verity digest\n", + src->dentry); + return -EIO; + } + return 0; + } + if (err < 0) + return err; + + src_digest[0] = (u8)verity_algo; + return ovl_check_setxattr(ofs, dst, OVL_XATTR_VERITY, + src_digest, 1 + hash_digest_size[verity_algo], -EOPNOTSUPP); +} + /* * ovl_sync_status() - Check fs sync status for volatile mounts *
During regular metacopy, if lowerdata file has fs-verity enabled, set the new overlay.verity xattr (if enabled). During real data copy up, remove any old overlay.verity xattr. If verity is required, and lowerdata does not have fs-verity enabled, fall back to full copy-up (or the generated metacopy would not validate). Signed-off-by: Alexander Larsson <alexl@redhat.com> --- fs/overlayfs/copy_up.c | 31 +++++++++++++++++++++++++++++++ fs/overlayfs/overlayfs.h | 3 +++ fs/overlayfs/util.c | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 1 deletion(-)