From acb0bcdbf914e0786352fd5c547c91b19327b225 Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Tue, 19 Jan 2016 13:12:02 -0600 Subject: [PATCH] UBUNTU: SAUCE: overlayfs: Skip permission checking for trusted.overlayfs.* xattrs The original mounter had CAP_SYS_ADMIN in the user namespace where the mount happened, and the vfs has validated that the user has permission to do the requested operation. This is sufficient for allowing the kernel to write these specific xattrs, so we can bypass the permission checks for these xattrs. To support this, export __vfs_setxattr_noperm and add an similar __vfs_removexattr_noperm which is also exported. Use these when setting or removing trusted.overlayfs.* xattrs. BugLink: http://bugs.launchpad.net/bugs/1531747 BugLink: http://bugs.launchpad.net/bugs/1534961 BugLink: http://bugs.launchpad.net/bugs/1535150 Signed-off-by: Seth Forshee Signed-off-by: Leann Ogasawara --- fs/overlayfs/overlayfs.h | 16 ++++++++++++++-- fs/xattr.c | 33 ++++++++++++++++++++++++++++++++- include/linux/xattr.h | 1 + 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index e218e741cb99..099cb8c25871 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -95,7 +95,13 @@ static inline int ovl_do_symlink(struct inode *dir, struct dentry *dentry, static inline int ovl_do_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - int err = vfs_setxattr(dentry, name, value, size, flags); + struct inode *inode = dentry->d_inode; + int err; + + inode_lock(inode); + err = __vfs_setxattr_noperm(dentry, name, value, size, flags); + inode_unlock(inode); + pr_debug("setxattr(%pd2, \"%s\", \"%*s\", 0x%x) = %i\n", dentry, name, (int) size, (char *) value, flags, err); return err; @@ -103,7 +109,13 @@ static inline int ovl_do_setxattr(struct dentry *dentry, const char *name, static inline int ovl_do_removexattr(struct dentry *dentry, const char *name) { - int err = vfs_removexattr(dentry, name); + struct inode *inode = dentry->d_inode; + int err; + + inode_lock(inode); + err = __vfs_removexattr_noperm(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 2d13b4e62fae..afd934343d28 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -202,6 +202,7 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name, return error; } +EXPORT_SYMBOL_GPL(__vfs_setxattr_noperm); int @@ -364,6 +365,36 @@ vfs_listxattr(struct dentry *dentry, char *list, size_t size) } EXPORT_SYMBOL_GPL(vfs_listxattr); +/** + * __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 dentry *dentry, const char *name) +{ + struct inode *inode = dentry->d_inode; + int error = -EOPNOTSUPP; + + if (inode->i_op->removexattr) { + error = inode->i_op->removexattr(dentry, name); + if (!error) { + fsnotify_xattr(dentry); + evm_inode_post_removexattr(dentry, name); + } + } + + return error; +} +EXPORT_SYMBOL_GPL(__vfs_removexattr_noperm); + int __vfs_removexattr(struct dentry *dentry, const char *name) { @@ -394,7 +425,7 @@ vfs_removexattr(struct dentry *dentry, const char *name) if (error) goto out; - error = __vfs_removexattr(dentry, name); + error = __vfs_removexattr_noperm(dentry, name); if (!error) { fsnotify_xattr(dentry); diff --git a/include/linux/xattr.h b/include/linux/xattr.h index e77605a0c8da..6fb2dfcaf99a 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -53,6 +53,7 @@ int __vfs_setxattr(struct dentry *, struct inode *, const char *, const void *, int __vfs_setxattr_noperm(struct dentry *, const char *, const void *, size_t, int); int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int); int __vfs_removexattr(struct dentry *, const char *); +int __vfs_removexattr_noperm(struct dentry *dentry, const char *name); int vfs_removexattr(struct dentry *, const char *); ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); -- 2.39.5