From 98e9cb5711c68223f0e4d5201b9a6add255ec550 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 2 Dec 2015 14:44:36 +0100 Subject: [PATCH] vfs: Distinguish between full xattr names and proper prefixes Add an additional "name" field to struct xattr_handler. When the name is set, the handler matches attributes with exactly that name. When the prefix is set instead, the handler matches attributes with the given prefix and with a non-empty suffix. This patch should avoid bugs like the one fixed in commit c361016a in the future. Signed-off-by: Andreas Gruenbacher Reviewed-by: James Morris Signed-off-by: Al Viro --- fs/9p/acl.c | 16 +++++----------- fs/9p/xattr.c | 4 ---- fs/ext2/xattr_security.c | 4 ---- fs/ext2/xattr_trusted.c | 4 ---- fs/ext2/xattr_user.c | 4 ---- fs/ext4/xattr_security.c | 4 ---- fs/ext4/xattr_trusted.c | 4 ---- fs/ext4/xattr_user.c | 4 ---- fs/f2fs/xattr.c | 20 ++++++-------------- fs/f2fs/xattr.h | 2 +- fs/hfsplus/xattr.c | 12 ------------ fs/jffs2/security.c | 6 ------ fs/jffs2/xattr_trusted.c | 4 ---- fs/jffs2/xattr_user.c | 4 ---- fs/nfs/nfs4proc.c | 8 +------- fs/ocfs2/xattr.c | 17 +---------------- fs/posix_acl.c | 10 +++------- fs/reiserfs/xattr.c | 3 ++- fs/squashfs/xattr.c | 3 --- fs/xattr.c | 27 +++++++++++++++++---------- fs/xfs/xfs_xattr.c | 6 ------ include/linux/xattr.h | 11 +++++++++++ 22 files changed, 47 insertions(+), 130 deletions(-) diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 6ff30b14bc76..9da967f38387 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -220,15 +220,12 @@ static int v9fs_xattr_get_acl(const struct xattr_handler *handler, struct posix_acl *acl; int error; - if (strcmp(name, "") != 0) - return -EINVAL; - v9ses = v9fs_dentry2v9ses(dentry); /* * We allow set/get/list of acl when access=client is not specified */ if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) - return v9fs_xattr_get(dentry, handler->prefix, buffer, size); + return v9fs_xattr_get(dentry, handler->name, buffer, size); acl = v9fs_get_cached_acl(d_inode(dentry), handler->flags); if (IS_ERR(acl)) @@ -250,16 +247,13 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler, struct v9fs_session_info *v9ses; struct inode *inode = d_inode(dentry); - if (strcmp(name, "") != 0) - return -EINVAL; - v9ses = v9fs_dentry2v9ses(dentry); /* * set the attribute on the remote. Without even looking at the * xattr value. We leave it to the server to validate */ if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) - return v9fs_xattr_set(dentry, handler->prefix, value, size, + return v9fs_xattr_set(dentry, handler->name, value, size, flags); if (S_ISLNK(inode->i_mode)) @@ -319,7 +313,7 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler, default: BUG(); } - retval = v9fs_xattr_set(dentry, handler->prefix, value, size, flags); + retval = v9fs_xattr_set(dentry, handler->name, value, size, flags); if (!retval) set_cached_acl(inode, handler->flags, acl); err_out: @@ -328,14 +322,14 @@ err_out: } const struct xattr_handler v9fs_xattr_acl_access_handler = { - .prefix = XATTR_NAME_POSIX_ACL_ACCESS, + .name = XATTR_NAME_POSIX_ACL_ACCESS, .flags = ACL_TYPE_ACCESS, .get = v9fs_xattr_get_acl, .set = v9fs_xattr_set_acl, }; const struct xattr_handler v9fs_xattr_acl_default_handler = { - .prefix = XATTR_NAME_POSIX_ACL_DEFAULT, + .name = XATTR_NAME_POSIX_ACL_DEFAULT, .flags = ACL_TYPE_DEFAULT, .get = v9fs_xattr_get_acl, .set = v9fs_xattr_set_acl, diff --git a/fs/9p/xattr.c b/fs/9p/xattr.c index e3d026ac382e..9dd9b47a6c1a 100644 --- a/fs/9p/xattr.c +++ b/fs/9p/xattr.c @@ -143,8 +143,6 @@ static int v9fs_xattr_handler_get(const struct xattr_handler *handler, { const char *full_name = xattr_full_name(handler, name); - if (strcmp(name, "") == 0) - return -EINVAL; return v9fs_xattr_get(dentry, full_name, buffer, size); } @@ -154,8 +152,6 @@ static int v9fs_xattr_handler_set(const struct xattr_handler *handler, { const char *full_name = xattr_full_name(handler, name); - if (strcmp(name, "") == 0) - return -EINVAL; return v9fs_xattr_set(dentry, full_name, value, size, flags); } diff --git a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c index dfb08750370d..118bf231bc7f 100644 --- a/fs/ext2/xattr_security.c +++ b/fs/ext2/xattr_security.c @@ -28,8 +28,6 @@ ext2_xattr_security_get(const struct xattr_handler *handler, struct dentry *dentry, const char *name, void *buffer, size_t size) { - if (strcmp(name, "") == 0) - return -EINVAL; return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_SECURITY, name, buffer, size); } @@ -39,8 +37,6 @@ ext2_xattr_security_set(const struct xattr_handler *handler, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - if (strcmp(name, "") == 0) - return -EINVAL; return ext2_xattr_set(d_inode(dentry), EXT2_XATTR_INDEX_SECURITY, name, value, size, flags); } diff --git a/fs/ext2/xattr_trusted.c b/fs/ext2/xattr_trusted.c index 3150dd3a7859..3f8f2bc6539e 100644 --- a/fs/ext2/xattr_trusted.c +++ b/fs/ext2/xattr_trusted.c @@ -32,8 +32,6 @@ ext2_xattr_trusted_get(const struct xattr_handler *handler, struct dentry *dentry, const char *name, void *buffer, size_t size) { - if (strcmp(name, "") == 0) - return -EINVAL; return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_TRUSTED, name, buffer, size); } @@ -43,8 +41,6 @@ ext2_xattr_trusted_set(const struct xattr_handler *handler, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - if (strcmp(name, "") == 0) - return -EINVAL; return ext2_xattr_set(d_inode(dentry), EXT2_XATTR_INDEX_TRUSTED, name, value, size, flags); } diff --git a/fs/ext2/xattr_user.c b/fs/ext2/xattr_user.c index 339a49bbb8ef..afd45ab1218c 100644 --- a/fs/ext2/xattr_user.c +++ b/fs/ext2/xattr_user.c @@ -34,8 +34,6 @@ ext2_xattr_user_get(const struct xattr_handler *handler, struct dentry *dentry, const char *name, void *buffer, size_t size) { - if (strcmp(name, "") == 0) - return -EINVAL; if (!test_opt(dentry->d_sb, XATTR_USER)) return -EOPNOTSUPP; return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_USER, @@ -47,8 +45,6 @@ ext2_xattr_user_set(const struct xattr_handler *handler, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - if (strcmp(name, "") == 0) - return -EINVAL; if (!test_opt(dentry->d_sb, XATTR_USER)) return -EOPNOTSUPP; diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c index 36f4c1a84c21..195abc4a88bb 100644 --- a/fs/ext4/xattr_security.c +++ b/fs/ext4/xattr_security.c @@ -33,8 +33,6 @@ ext4_xattr_security_get(const struct xattr_handler *handler, struct dentry *dentry, const char *name, void *buffer, size_t size) { - if (strcmp(name, "") == 0) - return -EINVAL; return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_SECURITY, name, buffer, size); } @@ -44,8 +42,6 @@ ext4_xattr_security_set(const struct xattr_handler *handler, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - if (strcmp(name, "") == 0) - return -EINVAL; return ext4_xattr_set(d_inode(dentry), EXT4_XATTR_INDEX_SECURITY, name, value, size, flags); } diff --git a/fs/ext4/xattr_trusted.c b/fs/ext4/xattr_trusted.c index 488089053342..121fdf9fdc02 100644 --- a/fs/ext4/xattr_trusted.c +++ b/fs/ext4/xattr_trusted.c @@ -36,8 +36,6 @@ ext4_xattr_trusted_get(const struct xattr_handler *handler, struct dentry *dentry, const char *name, void *buffer, size_t size) { - if (strcmp(name, "") == 0) - return -EINVAL; return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_TRUSTED, name, buffer, size); } @@ -47,8 +45,6 @@ ext4_xattr_trusted_set(const struct xattr_handler *handler, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - if (strcmp(name, "") == 0) - return -EINVAL; return ext4_xattr_set(d_inode(dentry), EXT4_XATTR_INDEX_TRUSTED, name, value, size, flags); } diff --git a/fs/ext4/xattr_user.c b/fs/ext4/xattr_user.c index d2dec3364062..577fc122d884 100644 --- a/fs/ext4/xattr_user.c +++ b/fs/ext4/xattr_user.c @@ -35,8 +35,6 @@ ext4_xattr_user_get(const struct xattr_handler *handler, struct dentry *dentry, const char *name, void *buffer, size_t size) { - if (strcmp(name, "") == 0) - return -EINVAL; if (!test_opt(dentry->d_sb, XATTR_USER)) return -EOPNOTSUPP; return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_USER, @@ -48,8 +46,6 @@ ext4_xattr_user_set(const struct xattr_handler *handler, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - if (strcmp(name, "") == 0) - return -EINVAL; if (!test_opt(dentry->d_sb, XATTR_USER)) return -EOPNOTSUPP; return ext4_xattr_set(d_inode(dentry), EXT4_XATTR_INDEX_USER, diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 862368a32e53..21cfe516034f 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -30,6 +30,7 @@ static size_t f2fs_xattr_generic_list(const struct xattr_handler *handler, const char *name, size_t len) { struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); + const char *prefix; int total_len, prefix_len; switch (handler->flags) { @@ -47,10 +48,11 @@ static size_t f2fs_xattr_generic_list(const struct xattr_handler *handler, return -EINVAL; } - prefix_len = strlen(handler->prefix); + prefix = xattr_prefix(handler); + prefix_len = strlen(prefix); total_len = prefix_len + len + 1; if (list && total_len <= list_size) { - memcpy(list, handler->prefix, prefix_len); + memcpy(list, prefix, prefix_len); memcpy(list + prefix_len, name, len); list[prefix_len + len] = '\0'; } @@ -77,8 +79,6 @@ static int f2fs_xattr_generic_get(const struct xattr_handler *handler, default: return -EINVAL; } - if (strcmp(name, "") == 0) - return -EINVAL; return f2fs_getxattr(d_inode(dentry), handler->flags, name, buffer, size, NULL); } @@ -103,9 +103,6 @@ static int f2fs_xattr_generic_set(const struct xattr_handler *handler, default: return -EINVAL; } - if (strcmp(name, "") == 0) - return -EINVAL; - return f2fs_setxattr(d_inode(dentry), handler->flags, name, value, size, NULL, flags); } @@ -114,7 +111,7 @@ static size_t f2fs_xattr_advise_list(const struct xattr_handler *handler, struct dentry *dentry, char *list, size_t list_size, const char *name, size_t len) { - const char *xname = F2FS_SYSTEM_ADVISE_PREFIX; + const char *xname = F2FS_SYSTEM_ADVISE_NAME; size_t size; size = strlen(xname) + 1; @@ -129,9 +126,6 @@ static int f2fs_xattr_advise_get(const struct xattr_handler *handler, { struct inode *inode = d_inode(dentry); - if (strcmp(name, "") != 0) - return -EINVAL; - if (buffer) *((char *)buffer) = F2FS_I(inode)->i_advise; return sizeof(char); @@ -143,8 +137,6 @@ static int f2fs_xattr_advise_set(const struct xattr_handler *handler, { struct inode *inode = d_inode(dentry); - if (strcmp(name, "") != 0) - return -EINVAL; if (!inode_owner_or_capable(inode)) return -EPERM; if (value == NULL) @@ -197,7 +189,7 @@ const struct xattr_handler f2fs_xattr_trusted_handler = { }; const struct xattr_handler f2fs_xattr_advise_handler = { - .prefix = F2FS_SYSTEM_ADVISE_PREFIX, + .name = F2FS_SYSTEM_ADVISE_NAME, .flags = F2FS_XATTR_INDEX_ADVISE, .list = f2fs_xattr_advise_list, .get = f2fs_xattr_advise_get, diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index 71a7100d5492..79dccc8252dd 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h @@ -27,7 +27,7 @@ #define F2FS_XATTR_REFCOUNT_MAX 1024 /* Name indexes */ -#define F2FS_SYSTEM_ADVISE_PREFIX "system.advise" +#define F2FS_SYSTEM_ADVISE_NAME "system.advise" #define F2FS_XATTR_INDEX_USER 1 #define F2FS_XATTR_INDEX_POSIX_ACL_ACCESS 2 #define F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT 3 diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c index e41a010cd89c..ab01530b4930 100644 --- a/fs/hfsplus/xattr.c +++ b/fs/hfsplus/xattr.c @@ -431,9 +431,6 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name, char *xattr_name; int res; - if (!strcmp(name, "")) - return -EINVAL; - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, GFP_KERNEL); if (!xattr_name) @@ -589,9 +586,6 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, int res; char *xattr_name; - if (!strcmp(name, "")) - return -EINVAL; - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, GFP_KERNEL); if (!xattr_name) @@ -853,9 +847,6 @@ static int hfsplus_osx_getxattr(const struct xattr_handler *handler, struct dentry *dentry, const char *name, void *buffer, size_t size) { - if (!strcmp(name, "")) - return -EINVAL; - /* * Don't allow retrieving properly prefixed attributes * by prepending them with "osx." @@ -876,9 +867,6 @@ static int hfsplus_osx_setxattr(const struct xattr_handler *handler, struct dentry *dentry, const char *name, const void *buffer, size_t size, int flags) { - if (!strcmp(name, "")) - return -EINVAL; - /* * Don't allow setting properly prefixed attributes * by prepending them with "osx." diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c index bf12fe5f83d7..ea79932cd665 100644 --- a/fs/jffs2/security.c +++ b/fs/jffs2/security.c @@ -52,9 +52,6 @@ static int jffs2_security_getxattr(const struct xattr_handler *handler, struct dentry *dentry, const char *name, void *buffer, size_t size) { - if (!strcmp(name, "")) - return -EINVAL; - return do_jffs2_getxattr(d_inode(dentry), JFFS2_XPREFIX_SECURITY, name, buffer, size); } @@ -63,9 +60,6 @@ static int jffs2_security_setxattr(const struct xattr_handler *handler, struct dentry *dentry, const char *name, const void *buffer, size_t size, int flags) { - if (!strcmp(name, "")) - return -EINVAL; - return do_jffs2_setxattr(d_inode(dentry), JFFS2_XPREFIX_SECURITY, name, buffer, size, flags); } diff --git a/fs/jffs2/xattr_trusted.c b/fs/jffs2/xattr_trusted.c index a562da0d6a26..8b55fe44c777 100644 --- a/fs/jffs2/xattr_trusted.c +++ b/fs/jffs2/xattr_trusted.c @@ -20,8 +20,6 @@ static int jffs2_trusted_getxattr(const struct xattr_handler *handler, struct dentry *dentry, const char *name, void *buffer, size_t size) { - if (!strcmp(name, "")) - return -EINVAL; return do_jffs2_getxattr(d_inode(dentry), JFFS2_XPREFIX_TRUSTED, name, buffer, size); } @@ -30,8 +28,6 @@ static int jffs2_trusted_setxattr(const struct xattr_handler *handler, struct dentry *dentry, const char *name, const void *buffer, size_t size, int flags) { - if (!strcmp(name, "")) - return -EINVAL; return do_jffs2_setxattr(d_inode(dentry), JFFS2_XPREFIX_TRUSTED, name, buffer, size, flags); } diff --git a/fs/jffs2/xattr_user.c b/fs/jffs2/xattr_user.c index cbc0472e59a8..b04335b84833 100644 --- a/fs/jffs2/xattr_user.c +++ b/fs/jffs2/xattr_user.c @@ -20,8 +20,6 @@ static int jffs2_user_getxattr(const struct xattr_handler *handler, struct dentry *dentry, const char *name, void *buffer, size_t size) { - if (!strcmp(name, "")) - return -EINVAL; return do_jffs2_getxattr(d_inode(dentry), JFFS2_XPREFIX_USER, name, buffer, size); } @@ -30,8 +28,6 @@ static int jffs2_user_setxattr(const struct xattr_handler *handler, struct dentry *dentry, const char *name, const void *buffer, size_t size, int flags) { - if (!strcmp(name, "")) - return -EINVAL; return do_jffs2_setxattr(d_inode(dentry), JFFS2_XPREFIX_USER, name, buffer, size, flags); } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 89818036f035..f6f40aae92b1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -6253,9 +6253,6 @@ static int nfs4_xattr_set_nfs4_acl(const struct xattr_handler *handler, const void *buf, size_t buflen, int flags) { - if (strcmp(key, "") != 0) - return -EINVAL; - return nfs4_proc_set_acl(d_inode(dentry), buf, buflen); } @@ -6263,9 +6260,6 @@ static int nfs4_xattr_get_nfs4_acl(const struct xattr_handler *handler, struct dentry *dentry, const char *key, void *buf, size_t buflen) { - if (strcmp(key, "") != 0) - return -EINVAL; - return nfs4_proc_get_acl(d_inode(dentry), buf, buflen); } @@ -8834,7 +8828,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = { }; static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = { - .prefix = XATTR_NAME_NFSV4_ACL, + .name = XATTR_NAME_NFSV4_ACL, .list = nfs4_xattr_list_nfs4_acl, .get = nfs4_xattr_get_nfs4_acl, .set = nfs4_xattr_set_nfs4_acl, diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index e9164f09841b..5823f985a662 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -544,8 +544,7 @@ static inline const char *ocfs2_xattr_prefix(int name_index) if (name_index > 0 && name_index < OCFS2_XATTR_MAX) handler = ocfs2_xattr_handler_map[name_index]; - - return handler ? handler->prefix : NULL; + return handler ? xattr_prefix(handler) : NULL; } static u32 ocfs2_xattr_name_hash(struct inode *inode, @@ -7249,8 +7248,6 @@ static int ocfs2_xattr_security_get(const struct xattr_handler *handler, struct dentry *dentry, const char *name, void *buffer, size_t size) { - if (strcmp(name, "") == 0) - return -EINVAL; return ocfs2_xattr_get(d_inode(dentry), OCFS2_XATTR_INDEX_SECURITY, name, buffer, size); } @@ -7259,9 +7256,6 @@ static int ocfs2_xattr_security_set(const struct xattr_handler *handler, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - if (strcmp(name, "") == 0) - return -EINVAL; - return ocfs2_xattr_set(d_inode(dentry), OCFS2_XATTR_INDEX_SECURITY, name, value, size, flags); } @@ -7345,8 +7339,6 @@ static int ocfs2_xattr_trusted_get(const struct xattr_handler *handler, struct dentry *dentry, const char *name, void *buffer, size_t size) { - if (strcmp(name, "") == 0) - return -EINVAL; return ocfs2_xattr_get(d_inode(dentry), OCFS2_XATTR_INDEX_TRUSTED, name, buffer, size); } @@ -7355,9 +7347,6 @@ static int ocfs2_xattr_trusted_set(const struct xattr_handler *handler, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - if (strcmp(name, "") == 0) - return -EINVAL; - return ocfs2_xattr_set(d_inode(dentry), OCFS2_XATTR_INDEX_TRUSTED, name, value, size, flags); } @@ -7398,8 +7387,6 @@ static int ocfs2_xattr_user_get(const struct xattr_handler *handler, { struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); - if (strcmp(name, "") == 0) - return -EINVAL; if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) return -EOPNOTSUPP; return ocfs2_xattr_get(d_inode(dentry), OCFS2_XATTR_INDEX_USER, name, @@ -7412,8 +7399,6 @@ static int ocfs2_xattr_user_set(const struct xattr_handler *handler, { struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); - if (strcmp(name, "") == 0) - return -EINVAL; if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) return -EOPNOTSUPP; diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 571465d6df58..17efd76978c8 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -769,8 +769,6 @@ posix_acl_xattr_get(const struct xattr_handler *handler, struct posix_acl *acl; int error; - if (strcmp(name, "") != 0) - return -EINVAL; if (!IS_POSIXACL(d_backing_inode(dentry))) return -EOPNOTSUPP; if (d_is_symlink(dentry)) @@ -797,8 +795,6 @@ posix_acl_xattr_set(const struct xattr_handler *handler, struct posix_acl *acl = NULL; int ret; - if (strcmp(name, "") != 0) - return -EINVAL; if (!IS_POSIXACL(inode)) return -EOPNOTSUPP; if (!inode->i_op->set_acl) @@ -832,7 +828,7 @@ posix_acl_xattr_list(const struct xattr_handler *handler, struct dentry *dentry, char *list, size_t list_size, const char *name, size_t name_len) { - const char *xname = handler->prefix; + const char *xname = handler->name; size_t size; if (!IS_POSIXACL(d_backing_inode(dentry))) @@ -845,7 +841,7 @@ posix_acl_xattr_list(const struct xattr_handler *handler, } const struct xattr_handler posix_acl_access_xattr_handler = { - .prefix = XATTR_NAME_POSIX_ACL_ACCESS, + .name = XATTR_NAME_POSIX_ACL_ACCESS, .flags = ACL_TYPE_ACCESS, .list = posix_acl_xattr_list, .get = posix_acl_xattr_get, @@ -854,7 +850,7 @@ const struct xattr_handler posix_acl_access_xattr_handler = { EXPORT_SYMBOL_GPL(posix_acl_access_xattr_handler); const struct xattr_handler posix_acl_default_xattr_handler = { - .prefix = XATTR_NAME_POSIX_ACL_DEFAULT, + .name = XATTR_NAME_POSIX_ACL_DEFAULT, .flags = ACL_TYPE_DEFAULT, .list = posix_acl_xattr_list, .get = posix_acl_xattr_get, diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 66b26fdfff8d..efe2ed3c13c5 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -756,7 +756,8 @@ find_xattr_handler_prefix(const struct xattr_handler **handlers, return NULL; for_each_xattr_handler(handlers, xah) { - if (strncmp(xah->prefix, name, strlen(xah->prefix)) == 0) + const char *prefix = xattr_prefix(xah); + if (strncmp(prefix, name, strlen(prefix)) == 0) break; } diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c index 6a4cc344085c..2f0ccbaa2d92 100644 --- a/fs/squashfs/xattr.c +++ b/fs/squashfs/xattr.c @@ -228,9 +228,6 @@ static int squashfs_xattr_handler_get(const struct xattr_handler *handler, struct dentry *d, const char *name, void *buffer, size_t size) { - if (name[0] == '\0') - return -EINVAL; - return squashfs_xattr_get(d_inode(d), handler->flags, name, buffer, size); } diff --git a/fs/xattr.c b/fs/xattr.c index 58bdabcc9d35..418ad691cf4e 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -681,13 +681,20 @@ xattr_resolve_name(const struct xattr_handler **handlers, const char **name) return NULL; for_each_xattr_handler(handlers, handler) { - const char *n = strcmp_prefix(*name, handler->prefix); + const char *n; + + n = strcmp_prefix(*name, xattr_prefix(handler)); if (n) { + if (!handler->prefix ^ !*n) { + if (*n) + continue; + return ERR_PTR(-EINVAL); + } *name = n; - break; + return handler; } } - return handler; + return ERR_PTR(-EOPNOTSUPP); } /* @@ -699,8 +706,8 @@ generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t s const struct xattr_handler *handler; handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name); - if (!handler) - return -EOPNOTSUPP; + if (IS_ERR(handler)) + return PTR_ERR(handler); return handler->get(handler, dentry, name, buffer, size); } @@ -746,8 +753,8 @@ generic_setxattr(struct dentry *dentry, const char *name, const void *value, siz if (size == 0) value = ""; /* empty EA, do not remove */ handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name); - if (!handler) - return -EOPNOTSUPP; + if (IS_ERR(handler)) + return PTR_ERR(handler); return handler->set(handler, dentry, name, value, size, flags); } @@ -761,8 +768,8 @@ generic_removexattr(struct dentry *dentry, const char *name) const struct xattr_handler *handler; handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name); - if (!handler) - return -EOPNOTSUPP; + if (IS_ERR(handler)) + return PTR_ERR(handler); return handler->set(handler, dentry, name, NULL, 0, XATTR_REPLACE); } @@ -789,7 +796,7 @@ EXPORT_SYMBOL(generic_removexattr); const char *xattr_full_name(const struct xattr_handler *handler, const char *name) { - size_t prefix_len = strlen(handler->prefix); + size_t prefix_len = strlen(xattr_prefix(handler)); return name - prefix_len; } diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index 7288795718c9..36a43851aac0 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -39,9 +39,6 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *dentry, struct xfs_inode *ip = XFS_I(d_inode(dentry)); int error, asize = size; - if (strcmp(name, "") == 0) - return -EINVAL; - /* Convert Linux syscall to XFS internal ATTR flags */ if (!size) { xflags |= ATTR_KERNOVAL; @@ -84,9 +81,6 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *dentry, struct xfs_inode *ip = XFS_I(d_inode(dentry)); int error; - if (strcmp(name, "") == 0) - return -EINVAL; - /* Convert Linux syscall to XFS internal ATTR flags */ if (flags & XATTR_CREATE) xflags |= ATTR_CREATE; diff --git a/include/linux/xattr.h b/include/linux/xattr.h index 45fa3456a0cc..03c847fb6cc1 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -19,7 +19,13 @@ struct inode; struct dentry; +/* + * struct xattr_handler: When @name is set, match attributes with exactly that + * name. When @prefix is set instead, match attributes with that prefix and + * with a non-empty suffix. + */ struct xattr_handler { + const char *name; const char *prefix; int flags; /* fs private flags */ size_t (*list)(const struct xattr_handler *, struct dentry *dentry, @@ -54,6 +60,11 @@ int generic_removexattr(struct dentry *dentry, const char *name); ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, size_t size, gfp_t flags); +static inline const char *xattr_prefix(const struct xattr_handler *handler) +{ + return handler->prefix ?: handler->name; +} + struct simple_xattrs { struct list_head head; spinlock_t lock; -- 2.20.1