overlayfs fixes for 5.2-rc6
-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQSQHSd0lITzzeNWNm3h3BK/laaZPAUCXQvlwwAKCRDh3BK/laaZ PJH4AP4vnumu1Q22ZWiGkTeU93JTgHt3MGPG1r1DtnUmsIKRfwEAjDY8bvuOP7Vw EYQicghvAPTHWqyGUoe0QZJwPlMiZw4= =TKOM -----END PGP SIGNATURE----- Merge tag 'ovl-fixes-5.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs Pull overlayfs fixes from Miklos Szeredi: "Fix two regressions in this cycle, and a couple of older bugs" * tag 'ovl-fixes-5.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: make i_ino consistent with st_ino in more cases ovl: fix typo in MODULE_PARM_DESC ovl: fix bogus -Wmaybe-unitialized warning ovl: don't fail with disconnected lower NFS ovl: fix wrong flags check in FS_IOC_FS[SG]ETXATTR ioctls
This commit is contained in:
commit
4ae004a9bc
|
@ -37,7 +37,7 @@ static int ovl_ccup_get(char *buf, const struct kernel_param *param)
|
|||
}
|
||||
|
||||
module_param_call(check_copy_up, ovl_ccup_set, ovl_ccup_get, NULL, 0644);
|
||||
MODULE_PARM_DESC(ovl_check_copy_up, "Obsolete; does nothing");
|
||||
MODULE_PARM_DESC(check_copy_up, "Obsolete; does nothing");
|
||||
|
||||
int ovl_copy_xattr(struct dentry *old, struct dentry *new)
|
||||
{
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
static unsigned short ovl_redirect_max = 256;
|
||||
module_param_named(redirect_max, ovl_redirect_max, ushort, 0644);
|
||||
MODULE_PARM_DESC(ovl_redirect_max,
|
||||
MODULE_PARM_DESC(redirect_max,
|
||||
"Maximum length of absolute redirect xattr value");
|
||||
|
||||
static int ovl_set_redirect(struct dentry *dentry, bool samedir);
|
||||
|
|
|
@ -409,37 +409,16 @@ static long ovl_real_ioctl(struct file *file, unsigned int cmd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int ovl_get_inode_flags(struct inode *inode)
|
||||
{
|
||||
unsigned int flags = READ_ONCE(inode->i_flags);
|
||||
unsigned int ovl_iflags = 0;
|
||||
|
||||
if (flags & S_SYNC)
|
||||
ovl_iflags |= FS_SYNC_FL;
|
||||
if (flags & S_APPEND)
|
||||
ovl_iflags |= FS_APPEND_FL;
|
||||
if (flags & S_IMMUTABLE)
|
||||
ovl_iflags |= FS_IMMUTABLE_FL;
|
||||
if (flags & S_NOATIME)
|
||||
ovl_iflags |= FS_NOATIME_FL;
|
||||
|
||||
return ovl_iflags;
|
||||
}
|
||||
|
||||
static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
unsigned long arg, unsigned int iflags)
|
||||
{
|
||||
long ret;
|
||||
struct inode *inode = file_inode(file);
|
||||
unsigned int flags;
|
||||
unsigned int old_flags;
|
||||
unsigned int old_iflags;
|
||||
|
||||
if (!inode_owner_or_capable(inode))
|
||||
return -EACCES;
|
||||
|
||||
if (get_user(flags, (int __user *) arg))
|
||||
return -EFAULT;
|
||||
|
||||
ret = mnt_want_write_file(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -448,8 +427,8 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd,
|
|||
|
||||
/* Check the capability before cred override */
|
||||
ret = -EPERM;
|
||||
old_flags = ovl_get_inode_flags(inode);
|
||||
if (((flags ^ old_flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) &&
|
||||
old_iflags = READ_ONCE(inode->i_flags);
|
||||
if (((iflags ^ old_iflags) & (S_APPEND | S_IMMUTABLE)) &&
|
||||
!capable(CAP_LINUX_IMMUTABLE))
|
||||
goto unlock;
|
||||
|
||||
|
@ -469,6 +448,63 @@ unlock:
|
|||
|
||||
}
|
||||
|
||||
static unsigned int ovl_fsflags_to_iflags(unsigned int flags)
|
||||
{
|
||||
unsigned int iflags = 0;
|
||||
|
||||
if (flags & FS_SYNC_FL)
|
||||
iflags |= S_SYNC;
|
||||
if (flags & FS_APPEND_FL)
|
||||
iflags |= S_APPEND;
|
||||
if (flags & FS_IMMUTABLE_FL)
|
||||
iflags |= S_IMMUTABLE;
|
||||
if (flags & FS_NOATIME_FL)
|
||||
iflags |= S_NOATIME;
|
||||
|
||||
return iflags;
|
||||
}
|
||||
|
||||
static long ovl_ioctl_set_fsflags(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
unsigned int flags;
|
||||
|
||||
if (get_user(flags, (int __user *) arg))
|
||||
return -EFAULT;
|
||||
|
||||
return ovl_ioctl_set_flags(file, cmd, arg,
|
||||
ovl_fsflags_to_iflags(flags));
|
||||
}
|
||||
|
||||
static unsigned int ovl_fsxflags_to_iflags(unsigned int xflags)
|
||||
{
|
||||
unsigned int iflags = 0;
|
||||
|
||||
if (xflags & FS_XFLAG_SYNC)
|
||||
iflags |= S_SYNC;
|
||||
if (xflags & FS_XFLAG_APPEND)
|
||||
iflags |= S_APPEND;
|
||||
if (xflags & FS_XFLAG_IMMUTABLE)
|
||||
iflags |= S_IMMUTABLE;
|
||||
if (xflags & FS_XFLAG_NOATIME)
|
||||
iflags |= S_NOATIME;
|
||||
|
||||
return iflags;
|
||||
}
|
||||
|
||||
static long ovl_ioctl_set_fsxflags(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct fsxattr fa;
|
||||
|
||||
memset(&fa, 0, sizeof(fa));
|
||||
if (copy_from_user(&fa, (void __user *) arg, sizeof(fa)))
|
||||
return -EFAULT;
|
||||
|
||||
return ovl_ioctl_set_flags(file, cmd, arg,
|
||||
ovl_fsxflags_to_iflags(fa.fsx_xflags));
|
||||
}
|
||||
|
||||
static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
long ret;
|
||||
|
@ -480,8 +516,11 @@ static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
break;
|
||||
|
||||
case FS_IOC_SETFLAGS:
|
||||
ret = ovl_ioctl_set_fsflags(file, cmd, arg);
|
||||
break;
|
||||
|
||||
case FS_IOC_FSSETXATTR:
|
||||
ret = ovl_ioctl_set_flags(file, cmd, arg);
|
||||
ret = ovl_ioctl_set_fsxflags(file, cmd, arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -553,15 +553,15 @@ static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev,
|
|||
int xinobits = ovl_xino_bits(inode->i_sb);
|
||||
|
||||
/*
|
||||
* When NFS export is enabled and d_ino is consistent with st_ino
|
||||
* (samefs or i_ino has enough bits to encode layer), set the same
|
||||
* value used for d_ino to i_ino, because nfsd readdirplus compares
|
||||
* d_ino values to i_ino values of child entries. When called from
|
||||
* When d_ino is consistent with st_ino (samefs or i_ino has enough
|
||||
* bits to encode layer), set the same value used for st_ino to i_ino,
|
||||
* so inode number exposed via /proc/locks and a like will be
|
||||
* consistent with d_ino and st_ino values. An i_ino value inconsistent
|
||||
* with d_ino also causes nfsd readdirplus to fail. When called from
|
||||
* ovl_new_inode(), ino arg is 0, so i_ino will be updated to real
|
||||
* upper inode i_ino on ovl_inode_init() or ovl_inode_update().
|
||||
*/
|
||||
if (inode->i_sb->s_export_op &&
|
||||
(ovl_same_sb(inode->i_sb) || xinobits)) {
|
||||
if (ovl_same_sb(inode->i_sb) || xinobits) {
|
||||
inode->i_ino = ino;
|
||||
if (xinobits && fsid && !(ino >> (64 - xinobits)))
|
||||
inode->i_ino |= (unsigned long)fsid << (64 - xinobits);
|
||||
|
|
|
@ -31,29 +31,29 @@ struct ovl_dir_cache;
|
|||
|
||||
static bool ovl_redirect_dir_def = IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_DIR);
|
||||
module_param_named(redirect_dir, ovl_redirect_dir_def, bool, 0644);
|
||||
MODULE_PARM_DESC(ovl_redirect_dir_def,
|
||||
MODULE_PARM_DESC(redirect_dir,
|
||||
"Default to on or off for the redirect_dir feature");
|
||||
|
||||
static bool ovl_redirect_always_follow =
|
||||
IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW);
|
||||
module_param_named(redirect_always_follow, ovl_redirect_always_follow,
|
||||
bool, 0644);
|
||||
MODULE_PARM_DESC(ovl_redirect_always_follow,
|
||||
MODULE_PARM_DESC(redirect_always_follow,
|
||||
"Follow redirects even if redirect_dir feature is turned off");
|
||||
|
||||
static bool ovl_index_def = IS_ENABLED(CONFIG_OVERLAY_FS_INDEX);
|
||||
module_param_named(index, ovl_index_def, bool, 0644);
|
||||
MODULE_PARM_DESC(ovl_index_def,
|
||||
MODULE_PARM_DESC(index,
|
||||
"Default to on or off for the inodes index feature");
|
||||
|
||||
static bool ovl_nfs_export_def = IS_ENABLED(CONFIG_OVERLAY_FS_NFS_EXPORT);
|
||||
module_param_named(nfs_export, ovl_nfs_export_def, bool, 0644);
|
||||
MODULE_PARM_DESC(ovl_nfs_export_def,
|
||||
MODULE_PARM_DESC(nfs_export,
|
||||
"Default to on or off for the NFS export feature");
|
||||
|
||||
static bool ovl_xino_auto_def = IS_ENABLED(CONFIG_OVERLAY_FS_XINO_AUTO);
|
||||
module_param_named(xino_auto, ovl_xino_auto_def, bool, 0644);
|
||||
MODULE_PARM_DESC(ovl_xino_auto_def,
|
||||
MODULE_PARM_DESC(xino_auto,
|
||||
"Auto enable xino feature");
|
||||
|
||||
static void ovl_entry_stack_free(struct ovl_entry *oe)
|
||||
|
@ -66,7 +66,7 @@ static void ovl_entry_stack_free(struct ovl_entry *oe)
|
|||
|
||||
static bool ovl_metacopy_def = IS_ENABLED(CONFIG_OVERLAY_FS_METACOPY);
|
||||
module_param_named(metacopy, ovl_metacopy_def, bool, 0644);
|
||||
MODULE_PARM_DESC(ovl_metacopy_def,
|
||||
MODULE_PARM_DESC(metacopy,
|
||||
"Default to on or off for the metadata only copy up feature");
|
||||
|
||||
static void ovl_dentry_release(struct dentry *dentry)
|
||||
|
@ -995,8 +995,8 @@ static int ovl_setup_trap(struct super_block *sb, struct dentry *dir,
|
|||
int err;
|
||||
|
||||
trap = ovl_get_trap_inode(sb, dir);
|
||||
err = PTR_ERR(trap);
|
||||
if (IS_ERR(trap)) {
|
||||
err = PTR_ERR_OR_ZERO(trap);
|
||||
if (err) {
|
||||
if (err == -ELOOP)
|
||||
pr_err("overlayfs: conflicting %s path\n", name);
|
||||
return err;
|
||||
|
@ -1471,23 +1471,20 @@ out_err:
|
|||
* Check if this layer root is a descendant of:
|
||||
* - another layer of this overlayfs instance
|
||||
* - upper/work dir of any overlayfs instance
|
||||
* - a disconnected dentry (detached root)
|
||||
*/
|
||||
static int ovl_check_layer(struct super_block *sb, struct dentry *dentry,
|
||||
const char *name)
|
||||
{
|
||||
struct dentry *next, *parent;
|
||||
bool is_root = false;
|
||||
struct dentry *next = dentry, *parent;
|
||||
int err = 0;
|
||||
|
||||
if (!dentry || dentry == dentry->d_sb->s_root)
|
||||
if (!dentry)
|
||||
return 0;
|
||||
|
||||
next = dget(dentry);
|
||||
/* Walk back ancestors to fs root (inclusive) looking for traps */
|
||||
do {
|
||||
parent = dget_parent(next);
|
||||
is_root = (parent == next);
|
||||
parent = dget_parent(next);
|
||||
|
||||
/* Walk back ancestors to root (inclusive) looking for traps */
|
||||
while (!err && parent != next) {
|
||||
if (ovl_is_inuse(parent)) {
|
||||
err = -EBUSY;
|
||||
pr_err("overlayfs: %s path overlapping in-use upperdir/workdir\n",
|
||||
|
@ -1496,17 +1493,12 @@ static int ovl_check_layer(struct super_block *sb, struct dentry *dentry,
|
|||
err = -ELOOP;
|
||||
pr_err("overlayfs: overlapping %s path\n", name);
|
||||
}
|
||||
dput(next);
|
||||
next = parent;
|
||||
} while (!err && !is_root);
|
||||
|
||||
/* Did we really walk to fs root or found a detached root? */
|
||||
if (!err && next != dentry->d_sb->s_root) {
|
||||
err = -ESTALE;
|
||||
pr_err("overlayfs: disconnected %s path\n", name);
|
||||
parent = dget_parent(next);
|
||||
dput(next);
|
||||
}
|
||||
|
||||
dput(next);
|
||||
dput(parent);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue