Message ID | 20190327235742.6236-1-lsahlber@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | cifs: fix kref underflow in close_shroot() | expand |
ср, 27 мар. 2019 г. в 16:58, Ronnie Sahlberg <lsahlber@redhat.com>: > > Fix a bug where we used to not initialize the cached fid structure at all > in open_shroot() if the open was successful but we did not get a lease. > This would leave the structure uninitialized and later when we close the handle > we would in close_shroot() try to kref_put() an uninitialized refcount. > > Fix this by always initializing this structure when we are about to return > 0/success but make the extra kref_get() on the refcount conditional to > whether we got a lease or not. > This extra get() is only used to hold the structure until we get a lease > break from the server at which point we will kref_put() it during lease > processing. > > Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> > --- > fs/cifs/smb2ops.c | 22 ++++++++++++++-------- > 1 file changed, 14 insertions(+), 8 deletions(-) > > diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c > index 1022a3771e14..4f0fb53cd0de 100644 > --- a/fs/cifs/smb2ops.c > +++ b/fs/cifs/smb2ops.c > @@ -724,14 +724,6 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) > else > goto oshr_exit; > > - > - memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid)); > - tcon->crfid.tcon = tcon; > - tcon->crfid.is_valid = true; > - kref_init(&tcon->crfid.refcount); > - kref_get(&tcon->crfid.refcount); > - > - > qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; > if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info)) > goto oshr_exit; > @@ -745,6 +737,20 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) > tcon->crfid.file_all_info_is_valid = 1; > > oshr_exit: > + /* > + * If we return 0/success then we must also initialize this struct. > + * If we got a lease we need to take out an extra get() to keep > + * the structure around until we receive the actual lease break. > + */ > + if (rc == 0) { ^^^ This will still leak a handle if smb2_validate_and_copy_iov failed above. -- Best regards, Pavel Shilovsky
On Thu, Mar 28, 2019 at 10:17 AM Pavel Shilovsky <piastryyy@gmail.com> wrote: > > ср, 27 мар. 2019 г. в 16:58, Ronnie Sahlberg <lsahlber@redhat.com>: > > > > Fix a bug where we used to not initialize the cached fid structure at all > > in open_shroot() if the open was successful but we did not get a lease. > > This would leave the structure uninitialized and later when we close the handle > > we would in close_shroot() try to kref_put() an uninitialized refcount. > > > > Fix this by always initializing this structure when we are about to return > > 0/success but make the extra kref_get() on the refcount conditional to > > whether we got a lease or not. > > This extra get() is only used to hold the structure until we get a lease > > break from the server at which point we will kref_put() it during lease > > processing. > > > > Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> > > --- > > fs/cifs/smb2ops.c | 22 ++++++++++++++-------- > > 1 file changed, 14 insertions(+), 8 deletions(-) > > > > diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c > > index 1022a3771e14..4f0fb53cd0de 100644 > > --- a/fs/cifs/smb2ops.c > > +++ b/fs/cifs/smb2ops.c > > @@ -724,14 +724,6 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) > > else > > goto oshr_exit; > > > > - > > - memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid)); > > - tcon->crfid.tcon = tcon; > > - tcon->crfid.is_valid = true; > > - kref_init(&tcon->crfid.refcount); > > - kref_get(&tcon->crfid.refcount); > > - > > - > > qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; > > if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info)) > > goto oshr_exit; > > @@ -745,6 +737,20 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) > > tcon->crfid.file_all_info_is_valid = 1; > > > > oshr_exit: > > + /* > > + * If we return 0/success then we must also initialize this struct. > > + * If we got a lease we need to take out an extra get() to keep > > + * the structure around until we receive the actual lease break. > > + */ > > + if (rc == 0) { > ^^^ > This will still leak a handle if smb2_validate_and_copy_iov failed above. Right. I will resend. > > -- > Best regards, > Pavel Shilovsky
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 1022a3771e14..4f0fb53cd0de 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -724,14 +724,6 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) else goto oshr_exit; - - memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid)); - tcon->crfid.tcon = tcon; - tcon->crfid.is_valid = true; - kref_init(&tcon->crfid.refcount); - kref_get(&tcon->crfid.refcount); - - qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info)) goto oshr_exit; @@ -745,6 +737,20 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) tcon->crfid.file_all_info_is_valid = 1; oshr_exit: + /* + * If we return 0/success then we must also initialize this struct. + * If we got a lease we need to take out an extra get() to keep + * the structure around until we receive the actual lease break. + */ + if (rc == 0) { + memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid)); + tcon->crfid.tcon = tcon; + tcon->crfid.is_valid = true; + kref_init(&tcon->crfid.refcount); + if (o_rsp && o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) + kref_get(&tcon->crfid.refcount); + } + mutex_unlock(&tcon->crfid.fid_mutex); SMB2_open_free(&rqst[0]); SMB2_query_info_free(&rqst[1]);
Fix a bug where we used to not initialize the cached fid structure at all in open_shroot() if the open was successful but we did not get a lease. This would leave the structure uninitialized and later when we close the handle we would in close_shroot() try to kref_put() an uninitialized refcount. Fix this by always initializing this structure when we are about to return 0/success but make the extra kref_get() on the refcount conditional to whether we got a lease or not. This extra get() is only used to hold the structure until we get a lease break from the server at which point we will kref_put() it during lease processing. Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> --- fs/cifs/smb2ops.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)