lkml.org 
[lkml]   [2019]   [Jul]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.2 279/413] CIFS: fix deadlock in cached root handling
    Date
    From: Aurelien Aptel <aaptel@suse.com>

    commit 7e5a70ad88b1e6f6d9b934b2efb41afff496820f upstream.

    Prevent deadlock between open_shroot() and
    cifs_mark_open_files_invalid() by releasing the lock before entering
    SMB2_open, taking it again after and checking if we still need to use
    the result.

    Link: https://lore.kernel.org/linux-cifs/684ed01c-cbca-2716-bc28-b0a59a0f8521@prodrive-technologies.com/T/#u
    Fixes: 3d4ef9a15343 ("smb3: fix redundant opens on root")
    Signed-off-by: Aurelien Aptel <aaptel@suse.com>
    Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
    Signed-off-by: Steve French <stfrench@microsoft.com>
    CC: Stable <stable@vger.kernel.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/cifs/smb2ops.c | 46 +++++++++++++++++++++++++++++++++++++++++++++-
    1 file changed, 45 insertions(+), 1 deletion(-)

    --- a/fs/cifs/smb2ops.c
    +++ b/fs/cifs/smb2ops.c
    @@ -694,8 +694,51 @@ int open_shroot(unsigned int xid, struct

    smb2_set_related(&rqst[1]);

    + /*
    + * We do not hold the lock for the open because in case
    + * SMB2_open needs to reconnect, it will end up calling
    + * cifs_mark_open_files_invalid() which takes the lock again
    + * thus causing a deadlock
    + */
    +
    + mutex_unlock(&tcon->crfid.fid_mutex);
    rc = compound_send_recv(xid, ses, flags, 2, rqst,
    resp_buftype, rsp_iov);
    + mutex_lock(&tcon->crfid.fid_mutex);
    +
    + /*
    + * Now we need to check again as the cached root might have
    + * been successfully re-opened from a concurrent process
    + */
    +
    + if (tcon->crfid.is_valid) {
    + /* work was already done */
    +
    + /* stash fids for close() later */
    + struct cifs_fid fid = {
    + .persistent_fid = pfid->persistent_fid,
    + .volatile_fid = pfid->volatile_fid,
    + };
    +
    + /*
    + * caller expects this func to set pfid to a valid
    + * cached root, so we copy the existing one and get a
    + * reference.
    + */
    + memcpy(pfid, tcon->crfid.fid, sizeof(*pfid));
    + kref_get(&tcon->crfid.refcount);
    +
    + mutex_unlock(&tcon->crfid.fid_mutex);
    +
    + if (rc == 0) {
    + /* close extra handle outside of crit sec */
    + SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
    + }
    + goto oshr_free;
    + }
    +
    + /* Cached root is still invalid, continue normaly */
    +
    if (rc)
    goto oshr_exit;

    @@ -729,8 +772,9 @@ int open_shroot(unsigned int xid, struct
    (char *)&tcon->crfid.file_all_info))
    tcon->crfid.file_all_info_is_valid = 1;

    - oshr_exit:
    +oshr_exit:
    mutex_unlock(&tcon->crfid.fid_mutex);
    +oshr_free:
    SMB2_open_free(&rqst[0]);
    SMB2_query_info_free(&rqst[1]);
    free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);

    \
     
     \ /
      Last update: 2019-07-24 21:36    [W:2.451 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site