* [PATCH v4] cifs: Fix leak when handling lease break for cached root fid
@ 2020-07-10 5:01 Paul Aurich
2020-07-11 16:41 ` Steve French
2020-07-29 14:02 ` Aurélien Aptel
0 siblings, 2 replies; 3+ messages in thread
From: Paul Aurich @ 2020-07-10 5:01 UTC (permalink / raw)
To: linux-cifs, sfrench; +Cc: paul, Ronnie Sahlberg, Aurélien Aptel
Handling a lease break for the cached root didn't free the
smb2_lease_break_work allocation, resulting in a leak:
unreferenced object 0xffff98383a5af480 (size 128):
comm "cifsd", pid 684, jiffies 4294936606 (age 534.868s)
hex dump (first 32 bytes):
c0 ff ff ff 1f 00 00 00 88 f4 5a 3a 38 98 ff ff ..........Z:8...
88 f4 5a 3a 38 98 ff ff 80 88 d6 8a ff ff ff ff ..Z:8...........
backtrace:
[<0000000068957336>] smb2_is_valid_oplock_break+0x1fa/0x8c0
[<0000000073b70b9e>] cifs_demultiplex_thread+0x73d/0xcc0
[<00000000905fa372>] kthread+0x11c/0x150
[<0000000079378e4e>] ret_from_fork+0x22/0x30
Avoid this leak by only allocating when necessary.
Fixes: a93864d93977 ("cifs: add lease tracking to the cached root fid")
Signed-off-by: Paul Aurich <paul@darkrain42.org>
CC: Stable <stable@vger.kernel.org> # v4.18+
---
Changes from v3:
- refactor pending open lease handling into separate functions so that the
core spinlock handling can occur all in smb2_is_valid_lease_break
fs/cifs/smb2misc.c | 73 +++++++++++++++++++++++++++++++++-------------
1 file changed, 52 insertions(+), 21 deletions(-)
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 6a39451973f8..865cd248c605 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -504,15 +504,31 @@ cifs_ses_oplock_break(struct work_struct *work)
kfree(lw);
}
+static void
+smb2_queue_pending_open_break(struct tcon_link *tlink, __u8 *lease_key,
+ __le32 new_lease_state)
+{
+ struct smb2_lease_break_work *lw;
+
+ lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
+ if (!lw) {
+ cifs_put_tlink(tlink);
+ return;
+ }
+
+ INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
+ lw->tlink = tlink;
+ lw->lease_state = new_lease_state;
+ memcpy(lw->lease_key, lease_key, SMB2_LEASE_KEY_SIZE);
+ queue_work(cifsiod_wq, &lw->lease_break);
+}
+
static bool
-smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
- struct smb2_lease_break_work *lw)
+smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp)
{
- bool found;
__u8 lease_state;
struct list_head *tmp;
struct cifsFileInfo *cfile;
- struct cifs_pending_open *open;
struct cifsInodeInfo *cinode;
int ack_req = le32_to_cpu(rsp->Flags &
SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
@@ -542,22 +558,29 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
cfile->oplock_level = lease_state;
cifs_queue_oplock_break(cfile);
- kfree(lw);
return true;
}
- found = false;
+ return false;
+}
+
+static struct cifs_pending_open *
+smb2_tcon_find_pending_open_lease(struct cifs_tcon *tcon,
+ struct smb2_lease_break *rsp)
+{
+ __u8 lease_state = le32_to_cpu(rsp->NewLeaseState);
+ int ack_req = le32_to_cpu(rsp->Flags &
+ SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
+ struct cifs_pending_open *open;
+ struct cifs_pending_open *found = NULL;
+
list_for_each_entry(open, &tcon->pending_opens, olist) {
if (memcmp(open->lease_key, rsp->LeaseKey,
SMB2_LEASE_KEY_SIZE))
continue;
if (!found && ack_req) {
- found = true;
- memcpy(lw->lease_key, open->lease_key,
- SMB2_LEASE_KEY_SIZE);
- lw->tlink = cifs_get_tlink(open->tlink);
- queue_work(cifsiod_wq, &lw->lease_break);
+ found = open;
}
cifs_dbg(FYI, "found in the pending open list\n");
@@ -578,14 +601,7 @@ smb2_is_valid_lease_break(char *buffer)
struct TCP_Server_Info *server;
struct cifs_ses *ses;
struct cifs_tcon *tcon;
- struct smb2_lease_break_work *lw;
-
- lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
- if (!lw)
- return false;
-
- INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
- lw->lease_state = rsp->NewLeaseState;
+ struct cifs_pending_open *open;
cifs_dbg(FYI, "Checking for lease break\n");
@@ -603,11 +619,27 @@ smb2_is_valid_lease_break(char *buffer)
spin_lock(&tcon->open_file_lock);
cifs_stats_inc(
&tcon->stats.cifs_stats.num_oplock_brks);
- if (smb2_tcon_has_lease(tcon, rsp, lw)) {
+ if (smb2_tcon_has_lease(tcon, rsp)) {
spin_unlock(&tcon->open_file_lock);
spin_unlock(&cifs_tcp_ses_lock);
return true;
}
+ open = smb2_tcon_find_pending_open_lease(tcon,
+ rsp);
+ if (open) {
+ __u8 lease_key[SMB2_LEASE_KEY_SIZE];
+ struct tcon_link *tlink;
+
+ tlink = cifs_get_tlink(open->tlink);
+ memcpy(lease_key, open->lease_key,
+ SMB2_LEASE_KEY_SIZE);
+ spin_unlock(&tcon->open_file_lock);
+ spin_unlock(&cifs_tcp_ses_lock);
+ smb2_queue_pending_open_break(tlink,
+ lease_key,
+ rsp->NewLeaseState);
+ return true;
+ }
spin_unlock(&tcon->open_file_lock);
if (tcon->crfid.is_valid &&
@@ -625,7 +657,6 @@ smb2_is_valid_lease_break(char *buffer)
}
}
spin_unlock(&cifs_tcp_ses_lock);
- kfree(lw);
cifs_dbg(FYI, "Can not process lease break - no lease matched\n");
return false;
}
--
2.27.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v4] cifs: Fix leak when handling lease break for cached root fid
2020-07-10 5:01 [PATCH v4] cifs: Fix leak when handling lease break for cached root fid Paul Aurich
@ 2020-07-11 16:41 ` Steve French
2020-07-29 14:02 ` Aurélien Aptel
1 sibling, 0 replies; 3+ messages in thread
From: Steve French @ 2020-07-11 16:41 UTC (permalink / raw)
To: Paul Aurich; +Cc: CIFS, Steve French, Ronnie Sahlberg, Aurélien Aptel
tentatively merged into cifs-2.6.git for-next pending review and testing
On Fri, Jul 10, 2020 at 12:01 AM Paul Aurich <paul@darkrain42.org> wrote:
>
> Handling a lease break for the cached root didn't free the
> smb2_lease_break_work allocation, resulting in a leak:
>
> unreferenced object 0xffff98383a5af480 (size 128):
> comm "cifsd", pid 684, jiffies 4294936606 (age 534.868s)
> hex dump (first 32 bytes):
> c0 ff ff ff 1f 00 00 00 88 f4 5a 3a 38 98 ff ff ..........Z:8...
> 88 f4 5a 3a 38 98 ff ff 80 88 d6 8a ff ff ff ff ..Z:8...........
> backtrace:
> [<0000000068957336>] smb2_is_valid_oplock_break+0x1fa/0x8c0
> [<0000000073b70b9e>] cifs_demultiplex_thread+0x73d/0xcc0
> [<00000000905fa372>] kthread+0x11c/0x150
> [<0000000079378e4e>] ret_from_fork+0x22/0x30
>
> Avoid this leak by only allocating when necessary.
>
> Fixes: a93864d93977 ("cifs: add lease tracking to the cached root fid")
> Signed-off-by: Paul Aurich <paul@darkrain42.org>
> CC: Stable <stable@vger.kernel.org> # v4.18+
> ---
> Changes from v3:
> - refactor pending open lease handling into separate functions so that the
> core spinlock handling can occur all in smb2_is_valid_lease_break
>
> fs/cifs/smb2misc.c | 73 +++++++++++++++++++++++++++++++++-------------
> 1 file changed, 52 insertions(+), 21 deletions(-)
>
> diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
> index 6a39451973f8..865cd248c605 100644
> --- a/fs/cifs/smb2misc.c
> +++ b/fs/cifs/smb2misc.c
> @@ -504,15 +504,31 @@ cifs_ses_oplock_break(struct work_struct *work)
> kfree(lw);
> }
>
> +static void
> +smb2_queue_pending_open_break(struct tcon_link *tlink, __u8 *lease_key,
> + __le32 new_lease_state)
> +{
> + struct smb2_lease_break_work *lw;
> +
> + lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
> + if (!lw) {
> + cifs_put_tlink(tlink);
> + return;
> + }
> +
> + INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
> + lw->tlink = tlink;
> + lw->lease_state = new_lease_state;
> + memcpy(lw->lease_key, lease_key, SMB2_LEASE_KEY_SIZE);
> + queue_work(cifsiod_wq, &lw->lease_break);
> +}
> +
> static bool
> -smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
> - struct smb2_lease_break_work *lw)
> +smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp)
> {
> - bool found;
> __u8 lease_state;
> struct list_head *tmp;
> struct cifsFileInfo *cfile;
> - struct cifs_pending_open *open;
> struct cifsInodeInfo *cinode;
> int ack_req = le32_to_cpu(rsp->Flags &
> SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
> @@ -542,22 +558,29 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
> cfile->oplock_level = lease_state;
>
> cifs_queue_oplock_break(cfile);
> - kfree(lw);
> return true;
> }
>
> - found = false;
> + return false;
> +}
> +
> +static struct cifs_pending_open *
> +smb2_tcon_find_pending_open_lease(struct cifs_tcon *tcon,
> + struct smb2_lease_break *rsp)
> +{
> + __u8 lease_state = le32_to_cpu(rsp->NewLeaseState);
> + int ack_req = le32_to_cpu(rsp->Flags &
> + SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
> + struct cifs_pending_open *open;
> + struct cifs_pending_open *found = NULL;
> +
> list_for_each_entry(open, &tcon->pending_opens, olist) {
> if (memcmp(open->lease_key, rsp->LeaseKey,
> SMB2_LEASE_KEY_SIZE))
> continue;
>
> if (!found && ack_req) {
> - found = true;
> - memcpy(lw->lease_key, open->lease_key,
> - SMB2_LEASE_KEY_SIZE);
> - lw->tlink = cifs_get_tlink(open->tlink);
> - queue_work(cifsiod_wq, &lw->lease_break);
> + found = open;
> }
>
> cifs_dbg(FYI, "found in the pending open list\n");
> @@ -578,14 +601,7 @@ smb2_is_valid_lease_break(char *buffer)
> struct TCP_Server_Info *server;
> struct cifs_ses *ses;
> struct cifs_tcon *tcon;
> - struct smb2_lease_break_work *lw;
> -
> - lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
> - if (!lw)
> - return false;
> -
> - INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
> - lw->lease_state = rsp->NewLeaseState;
> + struct cifs_pending_open *open;
>
> cifs_dbg(FYI, "Checking for lease break\n");
>
> @@ -603,11 +619,27 @@ smb2_is_valid_lease_break(char *buffer)
> spin_lock(&tcon->open_file_lock);
> cifs_stats_inc(
> &tcon->stats.cifs_stats.num_oplock_brks);
> - if (smb2_tcon_has_lease(tcon, rsp, lw)) {
> + if (smb2_tcon_has_lease(tcon, rsp)) {
> spin_unlock(&tcon->open_file_lock);
> spin_unlock(&cifs_tcp_ses_lock);
> return true;
> }
> + open = smb2_tcon_find_pending_open_lease(tcon,
> + rsp);
> + if (open) {
> + __u8 lease_key[SMB2_LEASE_KEY_SIZE];
> + struct tcon_link *tlink;
> +
> + tlink = cifs_get_tlink(open->tlink);
> + memcpy(lease_key, open->lease_key,
> + SMB2_LEASE_KEY_SIZE);
> + spin_unlock(&tcon->open_file_lock);
> + spin_unlock(&cifs_tcp_ses_lock);
> + smb2_queue_pending_open_break(tlink,
> + lease_key,
> + rsp->NewLeaseState);
> + return true;
> + }
> spin_unlock(&tcon->open_file_lock);
>
> if (tcon->crfid.is_valid &&
> @@ -625,7 +657,6 @@ smb2_is_valid_lease_break(char *buffer)
> }
> }
> spin_unlock(&cifs_tcp_ses_lock);
> - kfree(lw);
> cifs_dbg(FYI, "Can not process lease break - no lease matched\n");
> return false;
> }
> --
> 2.27.0
>
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v4] cifs: Fix leak when handling lease break for cached root fid
2020-07-10 5:01 [PATCH v4] cifs: Fix leak when handling lease break for cached root fid Paul Aurich
2020-07-11 16:41 ` Steve French
@ 2020-07-29 14:02 ` Aurélien Aptel
1 sibling, 0 replies; 3+ messages in thread
From: Aurélien Aptel @ 2020-07-29 14:02 UTC (permalink / raw)
To: Paul Aurich, linux-cifs, sfrench; +Cc: paul, Ronnie Sahlberg
Sorry for the delay...
Reviewed-by: Aurelien Aptel <aaptel@suse.com>
--
Aurélien Aptel / SUSE Labs Samba Team
GPG: 1839 CB5F 9F5B FB9B AA97 8C99 03C8 A49B 521B D5D3
SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg, DE
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah HRB 247165 (AG München)
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2020-07-29 14:03 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-10 5:01 [PATCH v4] cifs: Fix leak when handling lease break for cached root fid Paul Aurich
2020-07-11 16:41 ` Steve French
2020-07-29 14:02 ` Aurélien Aptel
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.