* [PATCH] cifs: fix kref underflow in close_shroot()
@ 2019-03-28 1:20 Ronnie Sahlberg
2019-03-28 5:10 ` Steve French
0 siblings, 1 reply; 7+ messages in thread
From: Ronnie Sahlberg @ 2019-03-28 1:20 UTC (permalink / raw)
To: linux-cifs; +Cc: Steve French, Pavel Shilovsky, Aurelien Aptel, Ronnie Sahlberg
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 if the open was successful
but only do the extra get() if we got a lease.
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 | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 1022a3771e14..7cfafac255aa 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -717,20 +717,18 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
oparms.fid->mid = le64_to_cpu(o_rsp->sync_hdr.MessageId);
#endif /* CIFS_DEBUG2 */
- if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
- oplock = smb2_parse_lease_state(server, o_rsp,
- &oparms.fid->epoch,
- oparms.fid->lease_key);
- 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);
+ if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
+ kref_get(&tcon->crfid.refcount);
+ oplock = smb2_parse_lease_state(server, o_rsp,
+ &oparms.fid->epoch,
+ oparms.fid->lease_key);
+ } else
+ goto oshr_exit;
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))
--
2.13.6
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] cifs: fix kref underflow in close_shroot()
2019-03-28 1:20 [PATCH] cifs: fix kref underflow in close_shroot() Ronnie Sahlberg
@ 2019-03-28 5:10 ` Steve French
2019-03-28 5:27 ` ronnie sahlberg
0 siblings, 1 reply; 7+ messages in thread
From: Steve French @ 2019-03-28 5:10 UTC (permalink / raw)
To: Ronnie Sahlberg; +Cc: linux-cifs, Pavel Shilovsky, Aurelien Aptel
Should this be CC:stable?
On Wed, Mar 27, 2019 at 8:21 PM Ronnie Sahlberg <lsahlber@redhat.com> wrote:
>
> 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 if the open was successful
> but only do the extra get() if we got a lease.
> 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 | 16 +++++++---------
> 1 file changed, 7 insertions(+), 9 deletions(-)
>
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index 1022a3771e14..7cfafac255aa 100644
> --- a/fs/cifs/smb2ops.c
> +++ b/fs/cifs/smb2ops.c
> @@ -717,20 +717,18 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
> oparms.fid->mid = le64_to_cpu(o_rsp->sync_hdr.MessageId);
> #endif /* CIFS_DEBUG2 */
>
> - if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
> - oplock = smb2_parse_lease_state(server, o_rsp,
> - &oparms.fid->epoch,
> - oparms.fid->lease_key);
> - 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);
>
> + if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
> + kref_get(&tcon->crfid.refcount);
> + oplock = smb2_parse_lease_state(server, o_rsp,
> + &oparms.fid->epoch,
> + oparms.fid->lease_key);
> + } else
> + goto oshr_exit;
>
> 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))
> --
> 2.13.6
>
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] cifs: fix kref underflow in close_shroot()
2019-03-28 5:10 ` Steve French
@ 2019-03-28 5:27 ` ronnie sahlberg
2019-03-28 19:06 ` Pavel Shilovsky
0 siblings, 1 reply; 7+ messages in thread
From: ronnie sahlberg @ 2019-03-28 5:27 UTC (permalink / raw)
To: Steve French; +Cc: Ronnie Sahlberg, linux-cifs, Pavel Shilovsky, Aurelien Aptel
Yeah, probably
On Thu, Mar 28, 2019 at 3:11 PM Steve French <smfrench@gmail.com> wrote:
>
> Should this be CC:stable?
>
> On Wed, Mar 27, 2019 at 8:21 PM Ronnie Sahlberg <lsahlber@redhat.com> wrote:
> >
> > 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 if the open was successful
> > but only do the extra get() if we got a lease.
> > 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 | 16 +++++++---------
> > 1 file changed, 7 insertions(+), 9 deletions(-)
> >
> > diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> > index 1022a3771e14..7cfafac255aa 100644
> > --- a/fs/cifs/smb2ops.c
> > +++ b/fs/cifs/smb2ops.c
> > @@ -717,20 +717,18 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
> > oparms.fid->mid = le64_to_cpu(o_rsp->sync_hdr.MessageId);
> > #endif /* CIFS_DEBUG2 */
> >
> > - if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
> > - oplock = smb2_parse_lease_state(server, o_rsp,
> > - &oparms.fid->epoch,
> > - oparms.fid->lease_key);
> > - 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);
> >
> > + if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
> > + kref_get(&tcon->crfid.refcount);
> > + oplock = smb2_parse_lease_state(server, o_rsp,
> > + &oparms.fid->epoch,
> > + oparms.fid->lease_key);
> > + } else
> > + goto oshr_exit;
> >
> > 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))
> > --
> > 2.13.6
> >
>
>
> --
> Thanks,
>
> Steve
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] cifs: fix kref underflow in close_shroot()
2019-03-28 5:27 ` ronnie sahlberg
@ 2019-03-28 19:06 ` Pavel Shilovsky
0 siblings, 0 replies; 7+ messages in thread
From: Pavel Shilovsky @ 2019-03-28 19:06 UTC (permalink / raw)
To: ronnie sahlberg
Cc: Steve French, Ronnie Sahlberg, linux-cifs, Pavel Shilovsky,
Aurelien Aptel
ср, 27 мар. 2019 г. в 22:27, ronnie sahlberg <ronniesahlberg@gmail.com>:
>
> Yeah, probably
>
> On Thu, Mar 28, 2019 at 3:11 PM Steve French <smfrench@gmail.com> wrote:
> >
> > Should this be CC:stable?
> >
> > On Wed, Mar 27, 2019 at 8:21 PM Ronnie Sahlberg <lsahlber@redhat.com> wrote:
> > >
> > > 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 if the open was successful
> > > but only do the extra get() if we got a lease.
> > > 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 | 16 +++++++---------
> > > 1 file changed, 7 insertions(+), 9 deletions(-)
> > >
> > > diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> > > index 1022a3771e14..7cfafac255aa 100644
> > > --- a/fs/cifs/smb2ops.c
> > > +++ b/fs/cifs/smb2ops.c
> > > @@ -717,20 +717,18 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
> > > oparms.fid->mid = le64_to_cpu(o_rsp->sync_hdr.MessageId);
> > > #endif /* CIFS_DEBUG2 */
> > >
> > > - if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
> > > - oplock = smb2_parse_lease_state(server, o_rsp,
> > > - &oparms.fid->epoch,
> > > - oparms.fid->lease_key);
> > > - 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);
> > >
> > > + if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
> > > + kref_get(&tcon->crfid.refcount);
> > > + oplock = smb2_parse_lease_state(server, o_rsp,
> > > + &oparms.fid->epoch,
> > > + oparms.fid->lease_key);
> > > + } else
> > > + goto oshr_exit;
> > >
> > > 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))
> > > --
> > > 2.13.6
> > >
> >
> >
> > --
> > Thanks,
> >
> > Steve
This part of the fix looks good but there is another piece remaining:
rc = smb2_validate_and_copy_iov(
le16_to_cpu(qi_rsp->OutputBufferOffset),
sizeof(struct smb2_file_all_info),
&rsp_iov[1], sizeof(struct smb2_file_all_info),
(char *)&tcon->crfid.file_all_info);
if (rc)
goto oshr_exit;
^^^
here RC is non-zero, but we are returning with 2 references on the
handle. The caller will assume that the open failed and doesn't call
close_shroot thus leaking one reference.
The result of smb2_validate_and_copy_iov only affects file_all_info
caching but doesn't affect the handle validity. So, RC needs to be
reset to 0 unconditionally here before returning from the function.
I checked v5.0 kernel and it doesn't seem it is affected by this bug
but it has the problem that it doesn't check whether server granted
the lease or not - probably it is not that bad to keep the reference
forever for non-leased opens, so leaving it for your choice to fix it
or not.
--
Best regards,
Pavel Shilovsky
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] cifs: fix kref underflow in close_shroot()
2019-03-28 0:17 ` Pavel Shilovsky
@ 2019-03-28 1:22 ` ronnie sahlberg
0 siblings, 0 replies; 7+ messages in thread
From: ronnie sahlberg @ 2019-03-28 1:22 UTC (permalink / raw)
To: Pavel Shilovsky
Cc: Ronnie Sahlberg, linux-cifs, Steve French, Pavel Shilovsky,
Aurelien Aptel
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
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] cifs: fix kref underflow in close_shroot()
2019-03-27 23:57 Ronnie Sahlberg
@ 2019-03-28 0:17 ` Pavel Shilovsky
2019-03-28 1:22 ` ronnie sahlberg
0 siblings, 1 reply; 7+ messages in thread
From: Pavel Shilovsky @ 2019-03-28 0:17 UTC (permalink / raw)
To: Ronnie Sahlberg; +Cc: linux-cifs, Steve French, Pavel Shilovsky, Aurelien Aptel
ср, 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
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH] cifs: fix kref underflow in close_shroot()
@ 2019-03-27 23:57 Ronnie Sahlberg
2019-03-28 0:17 ` Pavel Shilovsky
0 siblings, 1 reply; 7+ messages in thread
From: Ronnie Sahlberg @ 2019-03-27 23:57 UTC (permalink / raw)
To: linux-cifs; +Cc: Steve French, Pavel Shilovsky, Aurelien Aptel, Ronnie Sahlberg
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) {
+ 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]);
--
2.13.6
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2019-03-28 19:06 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-28 1:20 [PATCH] cifs: fix kref underflow in close_shroot() Ronnie Sahlberg
2019-03-28 5:10 ` Steve French
2019-03-28 5:27 ` ronnie sahlberg
2019-03-28 19:06 ` Pavel Shilovsky
-- strict thread matches above, loose matches on Subject: below --
2019-03-27 23:57 Ronnie Sahlberg
2019-03-28 0:17 ` Pavel Shilovsky
2019-03-28 1:22 ` ronnie sahlberg
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.