diff options
Diffstat (limited to 'fs/overlayfs/super.c')
| -rw-r--r-- | fs/overlayfs/super.c | 43 | 
1 files changed, 30 insertions, 13 deletions
| diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 5d972e6cd3fe..ce02f46029da 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -42,6 +42,8 @@ struct ovl_fs {  	long lower_namelen;  	/* pathnames of lower and upper dirs, for show_options */  	struct ovl_config config; +	/* creds of process who forced instantiation of super block */ +	const struct cred *creator_cred;  };  struct ovl_dir_cache; @@ -265,6 +267,13 @@ bool ovl_is_whiteout(struct dentry *dentry)  	return inode && IS_WHITEOUT(inode);  } +const struct cred *ovl_override_creds(struct super_block *sb) +{ +	struct ovl_fs *ofs = sb->s_fs_info; + +	return override_creds(ofs->creator_cred); +} +  static bool ovl_is_opaquedir(struct dentry *dentry)  {  	int res; @@ -274,7 +283,7 @@ static bool ovl_is_opaquedir(struct dentry *dentry)  	if (!S_ISDIR(inode->i_mode) || !inode->i_op->getxattr)  		return false; -	res = inode->i_op->getxattr(dentry, OVL_XATTR_OPAQUE, &val, 1); +	res = inode->i_op->getxattr(dentry, inode, OVL_XATTR_OPAQUE, &val, 1);  	if (res == 1 && val == 'y')  		return true; @@ -411,9 +420,7 @@ static inline struct dentry *ovl_lookup_real(struct dentry *dir,  {  	struct dentry *dentry; -	inode_lock(dir->d_inode); -	dentry = lookup_one_len(name->name, dir, name->len); -	inode_unlock(dir->d_inode); +	dentry = lookup_hash(name, dir);  	if (IS_ERR(dentry)) {  		if (PTR_ERR(dentry) == -ENOENT) @@ -605,6 +612,7 @@ static void ovl_put_super(struct super_block *sb)  	kfree(ufs->config.lowerdir);  	kfree(ufs->config.upperdir);  	kfree(ufs->config.workdir); +	put_cred(ufs->creator_cred);  	kfree(ufs);  } @@ -1066,16 +1074,19 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)  		/*  		 * Upper should support d_type, else whiteouts are visible.  		 * Given workdir and upper are on same fs, we can do -		 * iterate_dir() on workdir. +		 * iterate_dir() on workdir. This check requires successful +		 * creation of workdir in previous step.  		 */ -		err = ovl_check_d_type_supported(&workpath); -		if (err < 0) -			goto out_put_workdir; +		if (ufs->workdir) { +			err = ovl_check_d_type_supported(&workpath); +			if (err < 0) +				goto out_put_workdir; -		if (!err) { -			pr_err("overlayfs: upper fs needs to support d_type.\n"); -			err = -EINVAL; -			goto out_put_workdir; +			if (!err) { +				pr_err("overlayfs: upper fs needs to support d_type.\n"); +				err = -EINVAL; +				goto out_put_workdir; +			}  		}  	} @@ -1110,10 +1121,14 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)  	else  		sb->s_d_op = &ovl_dentry_operations; +	ufs->creator_cred = prepare_creds(); +	if (!ufs->creator_cred) +		goto out_put_lower_mnt; +  	err = -ENOMEM;  	oe = ovl_alloc_entry(numlower);  	if (!oe) -		goto out_put_lower_mnt; +		goto out_put_cred;  	root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe));  	if (!root_dentry) @@ -1146,6 +1161,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)  out_free_oe:  	kfree(oe); +out_put_cred: +	put_cred(ufs->creator_cred);  out_put_lower_mnt:  	for (i = 0; i < ufs->numlower; i++)  		mntput(ufs->lower_mnt[i]); | 
