lkml.org 
[lkml]   [2017]   [May]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.10 58/62] ceph: fix recursion between ceph_set_acl() and __ceph_setattr()
    Date
    4.10-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Yan, Zheng <zyan@redhat.com>

    commit 8179a101eb5f4ef0ac9a915fcea9a9d3109efa90 upstream.

    ceph_set_acl() calls __ceph_setattr() if the setacl operation needs
    to modify inode's i_mode. __ceph_setattr() updates inode's i_mode,
    then calls posix_acl_chmod().

    The problem is that __ceph_setattr() calls posix_acl_chmod() before
    sending the setattr request. The get_acl() call in posix_acl_chmod()
    can trigger a getxattr request. The reply of the getxattr request
    can restore inode's i_mode to its old value. The set_acl() call in
    posix_acl_chmod() sees old value of inode's i_mode, so it calls
    __ceph_setattr() again.

    Link: http://tracker.ceph.com/issues/19688
    Reported-by: Jerry Lee <leisurelysw24@gmail.com>
    Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
    Reviewed-by: Jeff Layton <jlayton@redhat.com>
    Tested-by: Luis Henriques <lhenriques@suse.com>
    Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/ceph/inode.c | 22 ++++++++++------------
    1 file changed, 10 insertions(+), 12 deletions(-)

    --- a/fs/ceph/inode.c
    +++ b/fs/ceph/inode.c
    @@ -2069,11 +2069,6 @@ int __ceph_setattr(struct inode *inode,
    if (inode_dirty_flags)
    __mark_inode_dirty(inode, inode_dirty_flags);

    - if (ia_valid & ATTR_MODE) {
    - err = posix_acl_chmod(inode, attr->ia_mode);
    - if (err)
    - goto out_put;
    - }

    if (mask) {
    req->r_inode = inode;
    @@ -2087,13 +2082,11 @@ int __ceph_setattr(struct inode *inode,
    ceph_cap_string(dirtied), mask);

    ceph_mdsc_put_request(req);
    - if (mask & CEPH_SETATTR_SIZE)
    - __ceph_do_pending_vmtruncate(inode);
    - ceph_free_cap_flush(prealloc_cf);
    - return err;
    -out_put:
    - ceph_mdsc_put_request(req);
    ceph_free_cap_flush(prealloc_cf);
    +
    + if (err >= 0 && (mask & CEPH_SETATTR_SIZE))
    + __ceph_do_pending_vmtruncate(inode);
    +
    return err;
    }

    @@ -2112,7 +2105,12 @@ int ceph_setattr(struct dentry *dentry,
    if (err != 0)
    return err;

    - return __ceph_setattr(inode, attr);
    + err = __ceph_setattr(inode, attr);
    +
    + if (err >= 0 && (attr->ia_valid & ATTR_MODE))
    + err = posix_acl_chmod(inode, attr->ia_mode);
    +
    + return err;
    }

    /*

    \
     
     \ /
      Last update: 2017-05-01 23:39    [W:2.326 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site