diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 1df7f850ff3bb..e523d600da4e8 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -251,8 +251,12 @@ static inline int ovl_do_setxattr(struct ovl_fs *ofs, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - int err = vfs_setxattr(ovl_upper_mnt_userns(ofs), dentry, name, - value, size, flags); + struct inode *inode = dentry->d_inode; + int err; + + inode_lock(inode); + err = __vfs_setxattr_noperm(&init_user_ns, dentry, name, value, size, flags); + inode_unlock(inode); pr_debug("setxattr(%pd2, \"%s\", \"%*pE\", %zu, %d) = %i\n", dentry, name, min((int)size, 48), value, size, flags, err); @@ -269,7 +273,13 @@ static inline int ovl_setxattr(struct ovl_fs *ofs, struct dentry *dentry, static inline int ovl_do_removexattr(struct ovl_fs *ofs, struct dentry *dentry, const char *name) { - int err = vfs_removexattr(ovl_upper_mnt_userns(ofs), dentry, name); + struct inode *inode = dentry->d_inode; + int err; + + inode_lock(inode); + err = __vfs_removexattr_noperm(&init_user_ns, dentry, name); + inode_unlock(inode); + pr_debug("removexattr(%pd2, \"%s\") = %i\n", dentry, name, err); return err; } diff --git a/fs/xattr.c b/fs/xattr.c index adab9a70b5368..76dc91ec7ae84 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -259,6 +259,7 @@ int __vfs_setxattr_noperm(struct user_namespace *mnt_userns, return error; } +EXPORT_SYMBOL_GPL(__vfs_setxattr_noperm); /** * __vfs_setxattr_locked - set an extended attribute while holding the inode @@ -499,6 +500,34 @@ __vfs_removexattr(struct user_namespace *mnt_userns, struct dentry *dentry, } EXPORT_SYMBOL(__vfs_removexattr); +/** + * __vfs_removexattr_noperm - perform removexattr operation without + * performing permission checks. + * + * @dentry - object to perform setxattr on + * @name - xattr name to set + * + * returns the result of the internal setxattr or setsecurity operations. + * + * This function requires the caller to lock the inode's i_mutex before it + * is executed. It also assumes that the caller will make the appropriate + * permission checks. + */ +int +__vfs_removexattr_noperm(struct user_namespace *mnt_userns, + struct dentry *dentry, const char *name) +{ + int error; + + error =__vfs_removexattr(mnt_userns, dentry, name); + if (!error) { + fsnotify_xattr(dentry); + evm_inode_post_removexattr(dentry, name); + } + return error; +} +EXPORT_SYMBOL_GPL(__vfs_removexattr_noperm); + /** * __vfs_removexattr_locked - set an extended attribute while holding the inode * lock @@ -529,12 +558,7 @@ __vfs_removexattr_locked(struct user_namespace *mnt_userns, if (error) goto out; - error = __vfs_removexattr(mnt_userns, dentry, name); - - if (!error) { - fsnotify_xattr(dentry); - evm_inode_post_removexattr(dentry, name); - } + error = __vfs_removexattr_noperm(mnt_userns, dentry, name); out: return error; diff --git a/include/linux/xattr.h b/include/linux/xattr.h index 2e7dd44926e4a..149b148625da4 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -69,6 +69,7 @@ int __vfs_setxattr_locked(struct user_namespace *, struct dentry *, int vfs_setxattr(struct user_namespace *, struct dentry *, const char *, const void *, size_t, int); int __vfs_removexattr(struct user_namespace *, struct dentry *, const char *); +int __vfs_removexattr_noperm(struct user_namespace *, struct dentry *, const char *); int __vfs_removexattr_locked(struct user_namespace *, struct dentry *, const char *, struct inode **); int vfs_removexattr(struct user_namespace *, struct dentry *, const char *);