diff options
author | Andreas Gruenbacher <agruen@kernel.org> | 2011-05-27 14:50:36 +0200 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-05-27 09:43:00 -0400 |
commit | 55b23bde19c08f14127a27d461a4e079942c7258 (patch) | |
tree | 074f23a530c5bbaccce7068bf2947bf39b60ab16 | |
parent | aa38572954ade525817fe88c54faebf85e5a61c0 (diff) | |
download | op-kernel-dev-55b23bde19c08f14127a27d461a4e079942c7258.zip op-kernel-dev-55b23bde19c08f14127a27d461a4e079942c7258.tar.gz |
xattr: Fix error results for non-existent / invisible attributes
Return -ENODATA when trying to read a user.* attribute which cannot
exist: user space otherwise does not have a reasonable way to
distinguish between non-existent and inaccessible attributes.
Likewise, return -ENODATA when an unprivileged process tries to read a
trusted.* attribute: to unprivileged processes, those attributes are
invisible (listxattr() won't include them).
Related to this bug report: https://bugzilla.redhat.com/660613
Signed-off-by: Andreas Gruenbacher <agruen@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/xattr.c | 16 |
1 files changed, 10 insertions, 6 deletions
@@ -46,18 +46,22 @@ xattr_permission(struct inode *inode, const char *name, int mask) return 0; /* - * The trusted.* namespace can only be accessed by a privileged user. + * The trusted.* namespace can only be accessed by privileged users. */ - if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) - return (capable(CAP_SYS_ADMIN) ? 0 : -EPERM); + if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) { + if (!capable(CAP_SYS_ADMIN)) + return (mask & MAY_WRITE) ? -EPERM : -ENODATA; + return 0; + } - /* In user.* namespace, only regular files and directories can have + /* + * In the user.* namespace, only regular files and directories can have * extended attributes. For sticky directories, only the owner and - * privileged user can write attributes. + * privileged users can write attributes. */ if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) { if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) - return -EPERM; + return (mask & MAY_WRITE) ? -EPERM : -ENODATA; if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) && (mask & MAY_WRITE) && !inode_owner_or_capable(inode)) return -EPERM; |