-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
skip permission checks for extended attributes #14220
Conversation
@amotin, @freqlabs, @anodos325. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is nice! I noticed the same issue one week ago but then was distracted by something else.
The fix looks good to me, I think a test case is worth to be added.
Thanks, @youzhongyang. @amotin suggested some modifications internally, I am testing those and will also add the test case. |
module/os/linux/zfs/zpl_xattr.c
Outdated
@@ -433,14 +433,26 @@ zpl_xattr_get(struct inode *ip, const char *name, void *value, size_t size) | |||
cred_t *cr = CRED(); | |||
fstrans_cookie_t cookie; | |||
int error; | |||
int xattr_lock = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be a boolean_t rather than an int.
module/os/linux/zfs/zfs_acl.c
Outdated
@@ -2465,6 +2465,8 @@ zfs_zaccess_trivial(znode_t *zp, uint32_t *working_mode, cred_t *cr, | |||
return (unmapped ? SET_ERROR(EPERM) : 0); | |||
} | |||
|
|||
rw_enter(&zp->z_gperm_lock, RW_READER); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This lock is only ever taken as a reader and doesn't provide any protection. Should this have been a RW_WRITER? Was the intent here to serial calls to generic_permission
or was it to safely set/clear zp->z_lockedxattr
. If the latter, couldn't we instead us the zp->z_lock
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. @amotin also pointed it out and I am working on an alternative solution. The lock was supposed to protect the generic_permission()
API as zp->z_lockedxattr
is global to each znode. So, the write locks on every permission check do not seem to be a good idea.
b27fd4f
to
11d64be
Compare
module/os/linux/zfs/zfs_vnops_os.c
Outdated
@@ -555,6 +555,7 @@ zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl, | |||
boolean_t fuid_dirtied; | |||
boolean_t have_acl = B_FALSE; | |||
boolean_t waited = B_FALSE; | |||
boolean_t skipaclchk = (flag & ATTR_NOACLCHECK) ?B_TRUE :B_FALSE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
skip_acl
for consistency, spacing around ternary operator
boolean_t skipaclchk = (flag & ATTR_NOACLCHECK) ?B_TRUE :B_FALSE; | |
boolean_t skip_acl = (flag & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did it to keep it in one line but will change.
module/os/freebsd/zfs/zfs_dir.c
Outdated
@@ -911,7 +912,7 @@ zfs_get_xattrdir(znode_t *zp, znode_t **xzpp, cred_t *cr, int flags) | |||
va.va_mode = S_IFDIR | S_ISVTX | 0777; | |||
zfs_fuid_map_ids(zp, cr, &va.va_uid, &va.va_gid); | |||
|
|||
error = zfs_make_xattrdir(zp, &va, xzpp, cr); | |||
error = zfs_make_xattrdir(zp, &va, xzpp, cr, B_FALSE); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While FreeBSD does not have this deadlock, could we make the code symmetric? If we do not check additional ACLs on Linux, why should we do it on FreeBSD?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I will update this for consistency. The boolean is not being used for FreeBSD but was added to make the build compatible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. I see Linux calls zfs_zaccess(), while FreeBSD doesn't at all, so there is nothing really to skip. So you may ignore that comment of mine. But now I wonder why is this there on Linux?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked and it was added during the initial commit while porting zfs on Linux 34dc7c2f2#diff-5c59a2f8d51fe5cd3ff56b5d01f01a9c7cd1a28b32a61a8bbc136bbc91e18da9R821. Since Linux kernel checks the permissions within VFS stack already, I am also not very sure if it's something we really need here or maybe it covers some edge case that I am not aware of.
@behlendorf.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@behlendorf Do you think if zfs_zaccess()
should be kept in zfs_make_xattrdir()
for Linux. FreeBSD does not have it and I am not sure if it's really required for Linux also.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ixhamza it seems to me this shouldn't be required for Linux either, and the VFS will be performing the needed access checks. If you can do some manual testing to make sure there's nothing obvious we're overlooking I think we can drop this. It's been so long I don't recall why it was originally added with the original port.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@behlendorf Thank you. I did some testing by setting/retrieving extended attributes and manipulating ACLs for different users and VFS already seems to be checking all the required permissions. I have also updated the PR.
85357d9
to
2280f07
Compare
zfs_zaccess_trivial() calls the generic_permission() to read xattr attributes. This causes deadlock if called from zpl_xattr_set_dir() context as xattr and the dent locks are already held in this scenario. This commit skips the permissions checks for extended attributes since the Linux VFS stack already checks it before passing us the control. Signed-off-by: Ameer Hamza <ahamza@ixsystems.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That worked out nicely.
zfs_zaccess_trivial() calls the generic_permission() to read xattr attributes. This causes deadlock if called from zpl_xattr_set_dir() context as xattr and the dent locks are already held in this scenario. This commit skips the permissions checks for extended attributes since the Linux VFS stack already checks it before passing us the control. Reviewed-by: Ryan Moeller <ryan@iXsystems.com> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Youzhong Yang <yyang@mathworks.com> Signed-off-by: Ameer Hamza <ahamza@ixsystems.com> Closes openzfs#14220
zfs_zaccess_trivial()
calls thegeneric_permission()
to read xattr attributes. This causes deadlock if called fromzpl_xattr_set_dir()
context as xattr and the dent locks are already held in this scenario. This commit skips the permissions checks for extended attributes since the Linux VFS stack already checks it before passing us the control.How Has This Been Tested?
Without this patch,
setfacl
would be deadlocked:Types of changes
Checklist:
Signed-off-by
.