diff options
author | Andreas Gruenbacher <agruenba@redhat.com> | 2015-12-02 14:44:36 +0100 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-12-06 21:33:52 -0500 |
commit | 98e9cb5711c68223f0e4d5201b9a6add255ec550 (patch) | |
tree | 12fee55d296fc85a6e8188368ca4944fc4d913a8 /fs/xattr.c | |
parent | 97d79299223baab330b194437e676d301f12d5f6 (diff) | |
download | lwn-98e9cb5711c68223f0e4d5201b9a6add255ec550.tar.gz lwn-98e9cb5711c68223f0e4d5201b9a6add255ec550.zip |
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 <agruenba@redhat.com>
Reviewed-by: James Morris <james.l.morris@oracle.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/xattr.c')
-rw-r--r-- | fs/xattr.c | 27 |
1 files changed, 17 insertions, 10 deletions
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; } |