Commit 4ae004a9 authored by Linus Torvalds's avatar Linus Torvalds

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
parents b910f6a7 6dde1e42
...@@ -37,7 +37,7 @@ static int ovl_ccup_get(char *buf, const struct kernel_param *param) ...@@ -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_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) int ovl_copy_xattr(struct dentry *old, struct dentry *new)
{ {
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
static unsigned short ovl_redirect_max = 256; static unsigned short ovl_redirect_max = 256;
module_param_named(redirect_max, ovl_redirect_max, ushort, 0644); 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"); "Maximum length of absolute redirect xattr value");
static int ovl_set_redirect(struct dentry *dentry, bool samedir); 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, ...@@ -409,37 +409,16 @@ static long ovl_real_ioctl(struct file *file, unsigned int cmd,
return ret; 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, static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg, unsigned int iflags)
{ {
long ret; long ret;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
unsigned int flags; unsigned int old_iflags;
unsigned int old_flags;
if (!inode_owner_or_capable(inode)) if (!inode_owner_or_capable(inode))
return -EACCES; return -EACCES;
if (get_user(flags, (int __user *) arg))
return -EFAULT;
ret = mnt_want_write_file(file); ret = mnt_want_write_file(file);
if (ret) if (ret)
return ret; return ret;
...@@ -448,8 +427,8 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd, ...@@ -448,8 +427,8 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd,
/* Check the capability before cred override */ /* Check the capability before cred override */
ret = -EPERM; ret = -EPERM;
old_flags = ovl_get_inode_flags(inode); old_iflags = READ_ONCE(inode->i_flags);
if (((flags ^ old_flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) && if (((iflags ^ old_iflags) & (S_APPEND | S_IMMUTABLE)) &&
!capable(CAP_LINUX_IMMUTABLE)) !capable(CAP_LINUX_IMMUTABLE))
goto unlock; goto unlock;
...@@ -469,6 +448,63 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd, ...@@ -469,6 +448,63 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd,
} }
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) static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{ {
long ret; long ret;
...@@ -480,8 +516,11 @@ static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -480,8 +516,11 @@ static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break; break;
case FS_IOC_SETFLAGS: case FS_IOC_SETFLAGS:
ret = ovl_ioctl_set_fsflags(file, cmd, arg);
break;
case FS_IOC_FSSETXATTR: case FS_IOC_FSSETXATTR:
ret = ovl_ioctl_set_flags(file, cmd, arg); ret = ovl_ioctl_set_fsxflags(file, cmd, arg);
break; break;
default: default:
......
...@@ -553,15 +553,15 @@ static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev, ...@@ -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); int xinobits = ovl_xino_bits(inode->i_sb);
/* /*
* When NFS export is enabled and d_ino is consistent with st_ino * When d_ino is consistent with st_ino (samefs or i_ino has enough
* (samefs or i_ino has enough bits to encode layer), set the same * bits to encode layer), set the same value used for st_ino to i_ino,
* value used for d_ino to i_ino, because nfsd readdirplus compares * so inode number exposed via /proc/locks and a like will be
* d_ino values to i_ino values of child entries. When called from * 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 * 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(). * upper inode i_ino on ovl_inode_init() or ovl_inode_update().
*/ */
if (inode->i_sb->s_export_op && if (ovl_same_sb(inode->i_sb) || xinobits) {
(ovl_same_sb(inode->i_sb) || xinobits)) {
inode->i_ino = ino; inode->i_ino = ino;
if (xinobits && fsid && !(ino >> (64 - xinobits))) if (xinobits && fsid && !(ino >> (64 - xinobits)))
inode->i_ino |= (unsigned long)fsid << (64 - xinobits); inode->i_ino |= (unsigned long)fsid << (64 - xinobits);
......
...@@ -31,29 +31,29 @@ struct ovl_dir_cache; ...@@ -31,29 +31,29 @@ struct ovl_dir_cache;
static bool ovl_redirect_dir_def = IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_DIR); 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_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"); "Default to on or off for the redirect_dir feature");
static bool ovl_redirect_always_follow = static bool ovl_redirect_always_follow =
IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW); IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW);
module_param_named(redirect_always_follow, ovl_redirect_always_follow, module_param_named(redirect_always_follow, ovl_redirect_always_follow,
bool, 0644); 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"); "Follow redirects even if redirect_dir feature is turned off");
static bool ovl_index_def = IS_ENABLED(CONFIG_OVERLAY_FS_INDEX); static bool ovl_index_def = IS_ENABLED(CONFIG_OVERLAY_FS_INDEX);
module_param_named(index, ovl_index_def, bool, 0644); 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"); "Default to on or off for the inodes index feature");
static bool ovl_nfs_export_def = IS_ENABLED(CONFIG_OVERLAY_FS_NFS_EXPORT); 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_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"); "Default to on or off for the NFS export feature");
static bool ovl_xino_auto_def = IS_ENABLED(CONFIG_OVERLAY_FS_XINO_AUTO); 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_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"); "Auto enable xino feature");
static void ovl_entry_stack_free(struct ovl_entry *oe) static void ovl_entry_stack_free(struct ovl_entry *oe)
...@@ -66,7 +66,7 @@ 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); static bool ovl_metacopy_def = IS_ENABLED(CONFIG_OVERLAY_FS_METACOPY);
module_param_named(metacopy, ovl_metacopy_def, bool, 0644); 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"); "Default to on or off for the metadata only copy up feature");
static void ovl_dentry_release(struct dentry *dentry) static void ovl_dentry_release(struct dentry *dentry)
...@@ -995,8 +995,8 @@ static int ovl_setup_trap(struct super_block *sb, struct dentry *dir, ...@@ -995,8 +995,8 @@ static int ovl_setup_trap(struct super_block *sb, struct dentry *dir,
int err; int err;
trap = ovl_get_trap_inode(sb, dir); trap = ovl_get_trap_inode(sb, dir);
err = PTR_ERR(trap); err = PTR_ERR_OR_ZERO(trap);
if (IS_ERR(trap)) { if (err) {
if (err == -ELOOP) if (err == -ELOOP)
pr_err("overlayfs: conflicting %s path\n", name); pr_err("overlayfs: conflicting %s path\n", name);
return err; return err;
...@@ -1471,23 +1471,20 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, ...@@ -1471,23 +1471,20 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb,
* Check if this layer root is a descendant of: * Check if this layer root is a descendant of:
* - another layer of this overlayfs instance * - another layer of this overlayfs instance
* - upper/work dir of any 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, static int ovl_check_layer(struct super_block *sb, struct dentry *dentry,
const char *name) const char *name)
{ {
struct dentry *next, *parent; struct dentry *next = dentry, *parent;
bool is_root = false;
int err = 0; int err = 0;
if (!dentry || dentry == dentry->d_sb->s_root) if (!dentry)
return 0; return 0;
next = dget(dentry); parent = dget_parent(next);
/* Walk back ancestors to fs root (inclusive) looking for traps */
do { /* Walk back ancestors to root (inclusive) looking for traps */
parent = dget_parent(next); while (!err && parent != next) {
is_root = (parent == next);
if (ovl_is_inuse(parent)) { if (ovl_is_inuse(parent)) {
err = -EBUSY; err = -EBUSY;
pr_err("overlayfs: %s path overlapping in-use upperdir/workdir\n", 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, ...@@ -1496,17 +1493,12 @@ static int ovl_check_layer(struct super_block *sb, struct dentry *dentry,
err = -ELOOP; err = -ELOOP;
pr_err("overlayfs: overlapping %s path\n", name); pr_err("overlayfs: overlapping %s path\n", name);
} }
dput(next);
next = parent; next = parent;
} while (!err && !is_root); parent = dget_parent(next);
dput(next);
/* 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);
} }
dput(next); dput(parent);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment