Skip to content

Commit

Permalink
Merge tag 'ovl-update-6.12' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/overlayfs/vfs

Pull overlayfs updates from Amir Goldstein:

 - Increase robustness of overlayfs to crashes in the case of underlying
   filesystems that to not guarantee metadata ordering to persistent
   storage (problem was reported with ubifs).

 - Deny mount inside container with features that require root
   privileges to work properly, instead of failing operations later.

 - Some clarifications to overlayfs documentation.

* tag 'ovl-update-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs:
  ovl: fail if trusted xattrs are needed but caller lacks permission
  overlayfs.rst: update metacopy section in overlayfs documentation
  ovl: fsync after metadata copy-up
  ovl: don't set the superblock's errseq_t manually
  • Loading branch information
Linus Torvalds committed Sep 19, 2024
2 parents 4a39ac5 + 6c4a5f9 commit 45d986d
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 19 deletions.
7 changes: 5 additions & 2 deletions Documentation/filesystems/overlayfs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,11 @@ Metadata only copy up

When the "metacopy" feature is enabled, overlayfs will only copy
up metadata (as opposed to whole file), when a metadata specific operation
like chown/chmod is performed. Full file will be copied up later when
file is opened for WRITE operation.
like chown/chmod is performed. An upper file in this state is marked with
"trusted.overlayfs.metacopy" xattr which indicates that the upper file
contains no data. The data will be copied up later when file is opened for
WRITE operation. After the lower file's data is copied up,
the "trusted.overlayfs.metacopy" xattr is removed from the upper file.

In other words, this is delayed data copy up operation and data is copied
up when there is a need to actually modify data.
Expand Down
43 changes: 39 additions & 4 deletions fs/overlayfs/copy_up.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,24 @@ static int ovl_verify_area(loff_t pos, loff_t pos2, loff_t len, loff_t totlen)
return 0;
}

static int ovl_sync_file(struct path *path)
{
struct file *new_file;
int err;

new_file = ovl_path_open(path, O_LARGEFILE | O_RDONLY);
if (IS_ERR(new_file))
return PTR_ERR(new_file);

err = vfs_fsync(new_file, 0);
fput(new_file);

return err;
}

static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
struct file *new_file, loff_t len)
struct file *new_file, loff_t len,
bool datasync)
{
struct path datapath;
struct file *old_file;
Expand Down Expand Up @@ -342,7 +358,8 @@ static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,

len -= bytes;
}
if (!error && ovl_should_sync(ofs))
/* call fsync once, either now or later along with metadata */
if (!error && ovl_should_sync(ofs) && datasync)
error = vfs_fsync(new_file, 0);
out_fput:
fput(old_file);
Expand Down Expand Up @@ -574,6 +591,7 @@ struct ovl_copy_up_ctx {
bool indexed;
bool metacopy;
bool metacopy_digest;
bool metadata_fsync;
};

static int ovl_link_up(struct ovl_copy_up_ctx *c)
Expand Down Expand Up @@ -634,7 +652,8 @@ static int ovl_copy_up_data(struct ovl_copy_up_ctx *c, const struct path *temp)
if (IS_ERR(new_file))
return PTR_ERR(new_file);

err = ovl_copy_up_file(ofs, c->dentry, new_file, c->stat.size);
err = ovl_copy_up_file(ofs, c->dentry, new_file, c->stat.size,
!c->metadata_fsync);
fput(new_file);

return err;
Expand Down Expand Up @@ -701,6 +720,10 @@ static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp)
err = ovl_set_attr(ofs, temp, &c->stat);
inode_unlock(temp->d_inode);

/* fsync metadata before moving it into upper dir */
if (!err && ovl_should_sync(ofs) && c->metadata_fsync)
err = ovl_sync_file(&upperpath);

return err;
}

Expand Down Expand Up @@ -860,7 +883,8 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)

temp = tmpfile->f_path.dentry;
if (!c->metacopy && c->stat.size) {
err = ovl_copy_up_file(ofs, c->dentry, tmpfile, c->stat.size);
err = ovl_copy_up_file(ofs, c->dentry, tmpfile, c->stat.size,
!c->metadata_fsync);
if (err)
goto out_fput;
}
Expand Down Expand Up @@ -1135,6 +1159,17 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
!kgid_has_mapping(current_user_ns(), ctx.stat.gid))
return -EOVERFLOW;

/*
* With metacopy disabled, we fsync after final metadata copyup, for
* both regular files and directories to get atomic copyup semantics
* on filesystems that do not use strict metadata ordering (e.g. ubifs).
*
* With metacopy enabled we want to avoid fsync on all meta copyup
* that will hurt performance of workloads such as chown -R, so we
* only fsync on data copyup as legacy behavior.
*/
ctx.metadata_fsync = !OVL_FS(dentry->d_sb)->config.metacopy &&
(S_ISREG(ctx.stat.mode) || S_ISDIR(ctx.stat.mode));
ctx.metacopy = ovl_need_meta_copy_up(dentry, ctx.stat.mode, flags);

if (parent) {
Expand Down
38 changes: 33 additions & 5 deletions fs/overlayfs/params.c
Original file line number Diff line number Diff line change
Expand Up @@ -755,11 +755,6 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx,
{
struct ovl_opt_set set = ctx->set;

if (ctx->nr_data > 0 && !config->metacopy) {
pr_err("lower data-only dirs require metacopy support.\n");
return -EINVAL;
}

/* Workdir/index are useless in non-upper mount */
if (!config->upperdir) {
if (config->workdir) {
Expand Down Expand Up @@ -911,6 +906,39 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx,
config->metacopy = false;
}

/*
* Fail if we don't have trusted xattr capability and a feature was
* explicitly requested that requires them.
*/
if (!config->userxattr && !capable(CAP_SYS_ADMIN)) {
if (set.redirect &&
config->redirect_mode != OVL_REDIRECT_NOFOLLOW) {
pr_err("redirect_dir requires permission to access trusted xattrs\n");
return -EPERM;
}
if (config->metacopy && set.metacopy) {
pr_err("metacopy requires permission to access trusted xattrs\n");
return -EPERM;
}
if (config->verity_mode) {
pr_err("verity requires permission to access trusted xattrs\n");
return -EPERM;
}
if (ctx->nr_data > 0) {
pr_err("lower data-only dirs require permission to access trusted xattrs\n");
return -EPERM;
}
/*
* Other xattr-dependent features should be disabled without
* great disturbance to the user in ovl_make_workdir().
*/
}

if (ctx->nr_data > 0 && !config->metacopy) {
pr_err("lower data-only dirs require metacopy support.\n");
return -EINVAL;
}

return 0;
}

Expand Down
10 changes: 2 additions & 8 deletions fs/overlayfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,15 +202,9 @@ static int ovl_sync_fs(struct super_block *sb, int wait)
int ret;

ret = ovl_sync_status(ofs);
/*
* We have to always set the err, because the return value isn't
* checked in syncfs, and instead indirectly return an error via
* the sb's writeback errseq, which VFS inspects after this call.
*/
if (ret < 0) {
errseq_set(&sb->s_wb_err, -EIO);

if (ret < 0)
return -EIO;
}

if (!ret)
return ret;
Expand Down

0 comments on commit 45d986d

Please sign in to comment.