Re: [4.13-rc1 regression] copyup crashes kernel when initializing selinux

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Jul 17, 2017 at 01:25:03PM +0200, Miklos Szeredi wrote:
> On Mon, Jul 17, 2017 at 05:37:41PM +0800, Eryu Guan wrote:
> > Hi all,
> > 
> > I hit a kernel crash with 4.13-rc1 kernel when running fstests
> > overlay/005. And git bisect pointed first bad to this commit
> > 
> > commit 09d8b586731bf589655c2ac971532c14cf272b63
> > Author: Miklos Szeredi <mszeredi@xxxxxxxxxx>
> > Date:   Tue Jul 4 22:03:16 2017 +0200
> > 
> >     ovl: move __upperdentry to ovl_inode
> > 
> >     Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxxxxx>
> > 
> > inode_doinit_with_dentry wants to read the upper inode's xattr to get
> > selinux information, and ovl_xattr_get() calls ovl_dentry_real(), which
> > depends on dentry->d_inode, but d_inode is null and not initialized yet
> > at this moment.
> > 
> > Mount overlay without selinux context mount option and trigger copyup
> > could reproduce the crash reliably. (The crash log I appended is from a
> > bisect run, so the kernel version is not exact 4.13-rc1.)
> 
> Could you please test following patch?

For me even simple "ls" was failing after mounting overlayfs. This patch
seems to fix that.

Vivek

> 
> Thanks,
> Miklos
> 
> ---
>  fs/overlayfs/inode.c     |   32 +++++++++++++++++---------------
>  fs/overlayfs/overlayfs.h |    7 ++++---
>  fs/overlayfs/super.c     |    8 ++++----
>  fs/overlayfs/util.c      |    7 ++++++-
>  4 files changed, 31 insertions(+), 23 deletions(-)
> 
> --- a/fs/overlayfs/inode.c
> +++ b/fs/overlayfs/inode.c
> @@ -202,37 +202,38 @@ bool ovl_is_private_xattr(const char *na
>  		       sizeof(OVL_XATTR_PREFIX) - 1) == 0;
>  }
>  
> -int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value,
> -		  size_t size, int flags)
> +int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
> +		  const void *value, size_t size, int flags)
>  {
>  	int err;
> -	struct path realpath;
> -	enum ovl_path_type type = ovl_path_real(dentry, &realpath);
> +	struct dentry *upperdentry = ovl_i_dentry_upper(inode);
> +	struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
>  	const struct cred *old_cred;
>  
>  	err = ovl_want_write(dentry);
>  	if (err)
>  		goto out;
>  
> -	if (!value && !OVL_TYPE_UPPER(type)) {
> -		err = vfs_getxattr(realpath.dentry, name, NULL, 0);
> +	if (!value && !upperdentry) {
> +		err = vfs_getxattr(realdentry, name, NULL, 0);
>  		if (err < 0)
>  			goto out_drop_write;
>  	}
>  
> -	err = ovl_copy_up(dentry);
> -	if (err)
> -		goto out_drop_write;
> +	if (!upperdentry) {
> +		err = ovl_copy_up(dentry);
> +		if (err)
> +			goto out_drop_write;
>  
> -	if (!OVL_TYPE_UPPER(type))
> -		ovl_path_upper(dentry, &realpath);
> +		realdentry = ovl_dentry_upper(dentry);
> +	}
>  
>  	old_cred = ovl_override_creds(dentry->d_sb);
>  	if (value)
> -		err = vfs_setxattr(realpath.dentry, name, value, size, flags);
> +		err = vfs_setxattr(realdentry, name, value, size, flags);
>  	else {
>  		WARN_ON(flags != XATTR_REPLACE);
> -		err = vfs_removexattr(realpath.dentry, name);
> +		err = vfs_removexattr(realdentry, name);
>  	}
>  	revert_creds(old_cred);
>  
> @@ -242,12 +243,13 @@ int ovl_xattr_set(struct dentry *dentry,
>  	return err;
>  }
>  
> -int ovl_xattr_get(struct dentry *dentry, const char *name,
> +int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
>  		  void *value, size_t size)
>  {
> -	struct dentry *realdentry = ovl_dentry_real(dentry);
>  	ssize_t res;
>  	const struct cred *old_cred;
> +	struct dentry *realdentry =
> +		ovl_i_dentry_upper(inode) ?: ovl_dentry_lower(dentry);
>  
>  	old_cred = ovl_override_creds(dentry->d_sb);
>  	res = vfs_getxattr(realdentry, name, value, size);
> --- a/fs/overlayfs/overlayfs.h
> +++ b/fs/overlayfs/overlayfs.h
> @@ -199,6 +199,7 @@ enum ovl_path_type ovl_path_real(struct
>  struct dentry *ovl_dentry_upper(struct dentry *dentry);
>  struct dentry *ovl_dentry_lower(struct dentry *dentry);
>  struct dentry *ovl_dentry_real(struct dentry *dentry);
> +struct dentry *ovl_i_dentry_upper(struct inode *inode);
>  struct inode *ovl_inode_upper(struct inode *inode);
>  struct inode *ovl_inode_lower(struct inode *inode);
>  struct inode *ovl_inode_real(struct inode *inode);
> @@ -270,9 +271,9 @@ int ovl_setattr(struct dentry *dentry, s
>  int ovl_getattr(const struct path *path, struct kstat *stat,
>  		u32 request_mask, unsigned int flags);
>  int ovl_permission(struct inode *inode, int mask);
> -int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value,
> -		  size_t size, int flags);
> -int ovl_xattr_get(struct dentry *dentry, const char *name,
> +int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
> +		  const void *value, size_t size, int flags);
> +int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
>  		  void *value, size_t size);
>  ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
>  struct posix_acl *ovl_get_acl(struct inode *inode, int type);
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -692,7 +692,7 @@ ovl_posix_acl_xattr_get(const struct xat
>  			struct dentry *dentry, struct inode *inode,
>  			const char *name, void *buffer, size_t size)
>  {
> -	return ovl_xattr_get(dentry, handler->name, buffer, size);
> +	return ovl_xattr_get(dentry, inode, handler->name, buffer, size);
>  }
>  
>  static int __maybe_unused
> @@ -742,7 +742,7 @@ ovl_posix_acl_xattr_set(const struct xat
>  			return err;
>  	}
>  
> -	err = ovl_xattr_set(dentry, handler->name, value, size, flags);
> +	err = ovl_xattr_set(dentry, inode, handler->name, value, size, flags);
>  	if (!err)
>  		ovl_copyattr(ovl_inode_real(inode), inode);
>  
> @@ -772,7 +772,7 @@ static int ovl_other_xattr_get(const str
>  			       struct dentry *dentry, struct inode *inode,
>  			       const char *name, void *buffer, size_t size)
>  {
> -	return ovl_xattr_get(dentry, name, buffer, size);
> +	return ovl_xattr_get(dentry, inode, name, buffer, size);
>  }
>  
>  static int ovl_other_xattr_set(const struct xattr_handler *handler,
> @@ -780,7 +780,7 @@ static int ovl_other_xattr_set(const str
>  			       const char *name, const void *value,
>  			       size_t size, int flags)
>  {
> -	return ovl_xattr_set(dentry, name, value, size, flags);
> +	return ovl_xattr_set(dentry, inode, name, value, size, flags);
>  }
>  
>  static const struct xattr_handler __maybe_unused
> --- a/fs/overlayfs/util.c
> +++ b/fs/overlayfs/util.c
> @@ -157,9 +157,14 @@ struct dentry *ovl_dentry_real(struct de
>  	return ovl_dentry_upper(dentry) ?: ovl_dentry_lower(dentry);
>  }
>  
> +struct dentry *ovl_i_dentry_upper(struct inode *inode)
> +{
> +	return ovl_upperdentry_dereference(OVL_I(inode));
> +}
> +
>  struct inode *ovl_inode_upper(struct inode *inode)
>  {
> -	struct dentry *upperdentry = ovl_upperdentry_dereference(OVL_I(inode));
> +	struct dentry *upperdentry = ovl_i_dentry_upper(inode);
>  
>  	return upperdentry ? d_inode(upperdentry) : NULL;
>  }
> --
> To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux