Skip to content

Commit d9710cc

Browse files
darkrain42gregkh
authored andcommitted
cifs: Fix leak when handling lease break for cached root fid
commit baf57b5 upstream. 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: a93864d ("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+ Reviewed-by: Aurelien Aptel <aaptel@suse.com> Signed-off-by: Steve French <stfrench@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 6ffc89c commit d9710cc

1 file changed

Lines changed: 52 additions & 21 deletions

File tree

fs/cifs/smb2misc.c

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -509,15 +509,31 @@ cifs_ses_oplock_break(struct work_struct *work)
509509
kfree(lw);
510510
}
511511

512+
static void
513+
smb2_queue_pending_open_break(struct tcon_link *tlink, __u8 *lease_key,
514+
__le32 new_lease_state)
515+
{
516+
struct smb2_lease_break_work *lw;
517+
518+
lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
519+
if (!lw) {
520+
cifs_put_tlink(tlink);
521+
return;
522+
}
523+
524+
INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
525+
lw->tlink = tlink;
526+
lw->lease_state = new_lease_state;
527+
memcpy(lw->lease_key, lease_key, SMB2_LEASE_KEY_SIZE);
528+
queue_work(cifsiod_wq, &lw->lease_break);
529+
}
530+
512531
static bool
513-
smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
514-
struct smb2_lease_break_work *lw)
532+
smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp)
515533
{
516-
bool found;
517534
__u8 lease_state;
518535
struct list_head *tmp;
519536
struct cifsFileInfo *cfile;
520-
struct cifs_pending_open *open;
521537
struct cifsInodeInfo *cinode;
522538
int ack_req = le32_to_cpu(rsp->Flags &
523539
SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
@@ -556,22 +572,29 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
556572
&cinode->flags);
557573

558574
cifs_queue_oplock_break(cfile);
559-
kfree(lw);
560575
return true;
561576
}
562577

563-
found = false;
578+
return false;
579+
}
580+
581+
static struct cifs_pending_open *
582+
smb2_tcon_find_pending_open_lease(struct cifs_tcon *tcon,
583+
struct smb2_lease_break *rsp)
584+
{
585+
__u8 lease_state = le32_to_cpu(rsp->NewLeaseState);
586+
int ack_req = le32_to_cpu(rsp->Flags &
587+
SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
588+
struct cifs_pending_open *open;
589+
struct cifs_pending_open *found = NULL;
590+
564591
list_for_each_entry(open, &tcon->pending_opens, olist) {
565592
if (memcmp(open->lease_key, rsp->LeaseKey,
566593
SMB2_LEASE_KEY_SIZE))
567594
continue;
568595

569596
if (!found && ack_req) {
570-
found = true;
571-
memcpy(lw->lease_key, open->lease_key,
572-
SMB2_LEASE_KEY_SIZE);
573-
lw->tlink = cifs_get_tlink(open->tlink);
574-
queue_work(cifsiod_wq, &lw->lease_break);
597+
found = open;
575598
}
576599

577600
cifs_dbg(FYI, "found in the pending open list\n");
@@ -592,14 +615,7 @@ smb2_is_valid_lease_break(char *buffer)
592615
struct TCP_Server_Info *server;
593616
struct cifs_ses *ses;
594617
struct cifs_tcon *tcon;
595-
struct smb2_lease_break_work *lw;
596-
597-
lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
598-
if (!lw)
599-
return false;
600-
601-
INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
602-
lw->lease_state = rsp->NewLeaseState;
618+
struct cifs_pending_open *open;
603619

604620
cifs_dbg(FYI, "Checking for lease break\n");
605621

@@ -617,11 +633,27 @@ smb2_is_valid_lease_break(char *buffer)
617633
spin_lock(&tcon->open_file_lock);
618634
cifs_stats_inc(
619635
&tcon->stats.cifs_stats.num_oplock_brks);
620-
if (smb2_tcon_has_lease(tcon, rsp, lw)) {
636+
if (smb2_tcon_has_lease(tcon, rsp)) {
621637
spin_unlock(&tcon->open_file_lock);
622638
spin_unlock(&cifs_tcp_ses_lock);
623639
return true;
624640
}
641+
open = smb2_tcon_find_pending_open_lease(tcon,
642+
rsp);
643+
if (open) {
644+
__u8 lease_key[SMB2_LEASE_KEY_SIZE];
645+
struct tcon_link *tlink;
646+
647+
tlink = cifs_get_tlink(open->tlink);
648+
memcpy(lease_key, open->lease_key,
649+
SMB2_LEASE_KEY_SIZE);
650+
spin_unlock(&tcon->open_file_lock);
651+
spin_unlock(&cifs_tcp_ses_lock);
652+
smb2_queue_pending_open_break(tlink,
653+
lease_key,
654+
rsp->NewLeaseState);
655+
return true;
656+
}
625657
spin_unlock(&tcon->open_file_lock);
626658

627659
if (tcon->crfid.is_valid &&
@@ -639,7 +671,6 @@ smb2_is_valid_lease_break(char *buffer)
639671
}
640672
}
641673
spin_unlock(&cifs_tcp_ses_lock);
642-
kfree(lw);
643674
cifs_dbg(FYI, "Can not process lease break - no lease matched\n");
644675
return false;
645676
}

0 commit comments

Comments
 (0)