Skip to content

Commit 4cb2c00

Browse files
committed
Merge tag 'ovl-fixes-5.11-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs fixes from Miklos Szeredi: - Fix capability conversion and minor overlayfs bugs that are related to the unprivileged overlay mounts introduced in this cycle. - Fix two recent (v5.10) and one old (v4.10) bug. - Clean up security xattr copy-up (related to a SELinux regression). * tag 'ovl-fixes-5.11-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: implement volatile-specific fsync error behaviour ovl: skip getxattr of security labels ovl: fix dentry leak in ovl_get_redirect ovl: avoid deadlock on directory ioctl cap: fix conversions on getxattr ovl: perform vfs_getxattr() with mounter creds ovl: add warning on user_ns mismatch
2 parents 6155670 + 335d3fc commit 4cb2c00

File tree

11 files changed

+136
-59
lines changed

11 files changed

+136
-59
lines changed

Documentation/filesystems/overlayfs.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,14 @@ without significant effort.
586586
The advantage of mounting with the "volatile" option is that all forms of
587587
sync calls to the upper filesystem are omitted.
588588

589+
In order to avoid a giving a false sense of safety, the syncfs (and fsync)
590+
semantics of volatile mounts are slightly different than that of the rest of
591+
VFS. If any writeback error occurs on the upperdir's filesystem after a
592+
volatile mount takes place, all sync functions will return an error. Once this
593+
condition is reached, the filesystem will not recover, and every subsequent sync
594+
call will return an error, even if the upperdir has not experience a new error
595+
since the last sync call.
596+
589597
When overlay is mounted with "volatile" option, the directory
590598
"$workdir/work/incompat/volatile" is created. During next mount, overlay
591599
checks for this directory and refuses to mount if present. This is a strong

fs/overlayfs/copy_up.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ int ovl_copy_xattr(struct super_block *sb, struct dentry *old,
8484

8585
if (ovl_is_private_xattr(sb, name))
8686
continue;
87+
88+
error = security_inode_copy_up_xattr(name);
89+
if (error < 0 && error != -EOPNOTSUPP)
90+
break;
91+
if (error == 1) {
92+
error = 0;
93+
continue; /* Discard */
94+
}
8795
retry:
8896
size = vfs_getxattr(old, name, value, value_size);
8997
if (size == -ERANGE)
@@ -107,13 +115,6 @@ int ovl_copy_xattr(struct super_block *sb, struct dentry *old,
107115
goto retry;
108116
}
109117

110-
error = security_inode_copy_up_xattr(name);
111-
if (error < 0 && error != -EOPNOTSUPP)
112-
break;
113-
if (error == 1) {
114-
error = 0;
115-
continue; /* Discard */
116-
}
117118
error = vfs_setxattr(new, name, value, size, 0);
118119
if (error) {
119120
if (error != -EOPNOTSUPP || ovl_must_copy_xattr(name))

fs/overlayfs/dir.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -992,8 +992,8 @@ static char *ovl_get_redirect(struct dentry *dentry, bool abs_redirect)
992992

993993
buflen -= thislen;
994994
memcpy(&buf[buflen], name, thislen);
995-
tmp = dget_dlock(d->d_parent);
996995
spin_unlock(&d->d_lock);
996+
tmp = dget_parent(d);
997997

998998
dput(d);
999999
d = tmp;

fs/overlayfs/file.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,9 @@ static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
398398
const struct cred *old_cred;
399399
int ret;
400400

401-
if (!ovl_should_sync(OVL_FS(file_inode(file)->i_sb)))
402-
return 0;
401+
ret = ovl_sync_status(OVL_FS(file_inode(file)->i_sb));
402+
if (ret <= 0)
403+
return ret;
403404

404405
ret = ovl_real_fdget_meta(file, &real, !datasync);
405406
if (ret)

fs/overlayfs/inode.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,9 @@ int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
352352
goto out;
353353

354354
if (!value && !upperdentry) {
355+
old_cred = ovl_override_creds(dentry->d_sb);
355356
err = vfs_getxattr(realdentry, name, NULL, 0);
357+
revert_creds(old_cred);
356358
if (err < 0)
357359
goto out_drop_write;
358360
}

fs/overlayfs/overlayfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ int ovl_check_metacopy_xattr(struct ovl_fs *ofs, struct dentry *dentry);
324324
bool ovl_is_metacopy_dentry(struct dentry *dentry);
325325
char *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct dentry *dentry,
326326
int padding);
327+
int ovl_sync_status(struct ovl_fs *ofs);
327328

328329
static inline bool ovl_is_impuredir(struct super_block *sb,
329330
struct dentry *dentry)

fs/overlayfs/ovl_entry.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ struct ovl_fs {
8181
atomic_long_t last_ino;
8282
/* Whiteout dentry cache */
8383
struct dentry *whiteout;
84+
/* r/o snapshot of upperdir sb's only taken on volatile mounts */
85+
errseq_t errseq;
8486
};
8587

8688
static inline struct vfsmount *ovl_upper_mnt(struct ovl_fs *ofs)

fs/overlayfs/readdir.c

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@ struct file *ovl_dir_real_file(const struct file *file, bool want_upper)
865865

866866
struct ovl_dir_file *od = file->private_data;
867867
struct dentry *dentry = file->f_path.dentry;
868-
struct file *realfile = od->realfile;
868+
struct file *old, *realfile = od->realfile;
869869

870870
if (!OVL_TYPE_UPPER(ovl_path_type(dentry)))
871871
return want_upper ? NULL : realfile;
@@ -874,29 +874,20 @@ struct file *ovl_dir_real_file(const struct file *file, bool want_upper)
874874
* Need to check if we started out being a lower dir, but got copied up
875875
*/
876876
if (!od->is_upper) {
877-
struct inode *inode = file_inode(file);
878-
879877
realfile = READ_ONCE(od->upperfile);
880878
if (!realfile) {
881879
struct path upperpath;
882880

883881
ovl_path_upper(dentry, &upperpath);
884882
realfile = ovl_dir_open_realfile(file, &upperpath);
883+
if (IS_ERR(realfile))
884+
return realfile;
885885

886-
inode_lock(inode);
887-
if (!od->upperfile) {
888-
if (IS_ERR(realfile)) {
889-
inode_unlock(inode);
890-
return realfile;
891-
}
892-
smp_store_release(&od->upperfile, realfile);
893-
} else {
894-
/* somebody has beaten us to it */
895-
if (!IS_ERR(realfile))
896-
fput(realfile);
897-
realfile = od->upperfile;
886+
old = cmpxchg_release(&od->upperfile, NULL, realfile);
887+
if (old) {
888+
fput(realfile);
889+
realfile = old;
898890
}
899-
inode_unlock(inode);
900891
}
901892
}
902893

@@ -909,8 +900,9 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
909900
struct file *realfile;
910901
int err;
911902

912-
if (!ovl_should_sync(OVL_FS(file->f_path.dentry->d_sb)))
913-
return 0;
903+
err = ovl_sync_status(OVL_FS(file->f_path.dentry->d_sb));
904+
if (err <= 0)
905+
return err;
914906

915907
realfile = ovl_dir_real_file(file, true);
916908
err = PTR_ERR_OR_ZERO(realfile);

fs/overlayfs/super.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,20 @@ static int ovl_sync_fs(struct super_block *sb, int wait)
264264
struct super_block *upper_sb;
265265
int ret;
266266

267-
if (!ovl_upper_mnt(ofs))
268-
return 0;
267+
ret = ovl_sync_status(ofs);
268+
/*
269+
* We have to always set the err, because the return value isn't
270+
* checked in syncfs, and instead indirectly return an error via
271+
* the sb's writeback errseq, which VFS inspects after this call.
272+
*/
273+
if (ret < 0) {
274+
errseq_set(&sb->s_wb_err, -EIO);
275+
return -EIO;
276+
}
277+
278+
if (!ret)
279+
return ret;
269280

270-
if (!ovl_should_sync(ofs))
271-
return 0;
272281
/*
273282
* Not called for sync(2) call or an emergency sync (SB_I_SKIP_SYNC).
274283
* All the super blocks will be iterated, including upper_sb.
@@ -1923,6 +1932,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
19231932
unsigned int numlower;
19241933
int err;
19251934

1935+
err = -EIO;
1936+
if (WARN_ON(sb->s_user_ns != current_user_ns()))
1937+
goto out;
1938+
19261939
sb->s_d_op = &ovl_dentry_operations;
19271940

19281941
err = -ENOMEM;
@@ -1989,6 +2002,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
19892002
sb->s_op = &ovl_super_operations;
19902003

19912004
if (ofs->config.upperdir) {
2005+
struct super_block *upper_sb;
2006+
19922007
if (!ofs->config.workdir) {
19932008
pr_err("missing 'workdir'\n");
19942009
goto out_err;
@@ -1998,16 +2013,25 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
19982013
if (err)
19992014
goto out_err;
20002015

2016+
upper_sb = ovl_upper_mnt(ofs)->mnt_sb;
2017+
if (!ovl_should_sync(ofs)) {
2018+
ofs->errseq = errseq_sample(&upper_sb->s_wb_err);
2019+
if (errseq_check(&upper_sb->s_wb_err, ofs->errseq)) {
2020+
err = -EIO;
2021+
pr_err("Cannot mount volatile when upperdir has an unseen error. Sync upperdir fs to clear state.\n");
2022+
goto out_err;
2023+
}
2024+
}
2025+
20012026
err = ovl_get_workdir(sb, ofs, &upperpath);
20022027
if (err)
20032028
goto out_err;
20042029

20052030
if (!ofs->workdir)
20062031
sb->s_flags |= SB_RDONLY;
20072032

2008-
sb->s_stack_depth = ovl_upper_mnt(ofs)->mnt_sb->s_stack_depth;
2009-
sb->s_time_gran = ovl_upper_mnt(ofs)->mnt_sb->s_time_gran;
2010-
2033+
sb->s_stack_depth = upper_sb->s_stack_depth;
2034+
sb->s_time_gran = upper_sb->s_time_gran;
20112035
}
20122036
oe = ovl_get_lowerstack(sb, splitlower, numlower, ofs, layers);
20132037
err = PTR_ERR(oe);

fs/overlayfs/util.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -962,3 +962,30 @@ char *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct dentry *dentry,
962962
kfree(buf);
963963
return ERR_PTR(res);
964964
}
965+
966+
/*
967+
* ovl_sync_status() - Check fs sync status for volatile mounts
968+
*
969+
* Returns 1 if this is not a volatile mount and a real sync is required.
970+
*
971+
* Returns 0 if syncing can be skipped because mount is volatile, and no errors
972+
* have occurred on the upperdir since the mount.
973+
*
974+
* Returns -errno if it is a volatile mount, and the error that occurred since
975+
* the last mount. If the error code changes, it'll return the latest error
976+
* code.
977+
*/
978+
979+
int ovl_sync_status(struct ovl_fs *ofs)
980+
{
981+
struct vfsmount *mnt;
982+
983+
if (ovl_should_sync(ofs))
984+
return 1;
985+
986+
mnt = ovl_upper_mnt(ofs);
987+
if (!mnt)
988+
return 0;
989+
990+
return errseq_check(&mnt->mnt_sb->s_wb_err, ofs->errseq);
991+
}

0 commit comments

Comments
 (0)