Skip to content

Commit baf57b5

Browse files
darkrain42smfrench
authored andcommitted
cifs: Fix leak when handling lease break for cached root fid
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 <[email protected]> CC: Stable <[email protected]> # v4.18+ Reviewed-by: Aurelien Aptel <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent bcf8768 commit baf57b5

File tree

1 file changed

+52
-21
lines changed

1 file changed

+52
-21
lines changed

fs/cifs/smb2misc.c

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

511+
static void
512+
smb2_queue_pending_open_break(struct tcon_link *tlink, __u8 *lease_key,
513+
__le32 new_lease_state)
514+
{
515+
struct smb2_lease_break_work *lw;
516+
517+
lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
518+
if (!lw) {
519+
cifs_put_tlink(tlink);
520+
return;
521+
}
522+
523+
INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
524+
lw->tlink = tlink;
525+
lw->lease_state = new_lease_state;
526+
memcpy(lw->lease_key, lease_key, SMB2_LEASE_KEY_SIZE);
527+
queue_work(cifsiod_wq, &lw->lease_break);
528+
}
529+
511530
static bool
512-
smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
513-
struct smb2_lease_break_work *lw)
531+
smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp)
514532
{
515-
bool found;
516533
__u8 lease_state;
517534
struct list_head *tmp;
518535
struct cifsFileInfo *cfile;
519-
struct cifs_pending_open *open;
520536
struct cifsInodeInfo *cinode;
521537
int ack_req = le32_to_cpu(rsp->Flags &
522538
SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
@@ -546,22 +562,29 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
546562
cfile->oplock_level = lease_state;
547563

548564
cifs_queue_oplock_break(cfile);
549-
kfree(lw);
550565
return true;
551566
}
552567

553-
found = false;
568+
return false;
569+
}
570+
571+
static struct cifs_pending_open *
572+
smb2_tcon_find_pending_open_lease(struct cifs_tcon *tcon,
573+
struct smb2_lease_break *rsp)
574+
{
575+
__u8 lease_state = le32_to_cpu(rsp->NewLeaseState);
576+
int ack_req = le32_to_cpu(rsp->Flags &
577+
SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
578+
struct cifs_pending_open *open;
579+
struct cifs_pending_open *found = NULL;
580+
554581
list_for_each_entry(open, &tcon->pending_opens, olist) {
555582
if (memcmp(open->lease_key, rsp->LeaseKey,
556583
SMB2_LEASE_KEY_SIZE))
557584
continue;
558585

559586
if (!found && ack_req) {
560-
found = true;
561-
memcpy(lw->lease_key, open->lease_key,
562-
SMB2_LEASE_KEY_SIZE);
563-
lw->tlink = cifs_get_tlink(open->tlink);
564-
queue_work(cifsiod_wq, &lw->lease_break);
587+
found = open;
565588
}
566589

567590
cifs_dbg(FYI, "found in the pending open list\n");
@@ -582,14 +605,7 @@ smb2_is_valid_lease_break(char *buffer)
582605
struct TCP_Server_Info *server;
583606
struct cifs_ses *ses;
584607
struct cifs_tcon *tcon;
585-
struct smb2_lease_break_work *lw;
586-
587-
lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
588-
if (!lw)
589-
return false;
590-
591-
INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
592-
lw->lease_state = rsp->NewLeaseState;
608+
struct cifs_pending_open *open;
593609

594610
cifs_dbg(FYI, "Checking for lease break\n");
595611

@@ -607,11 +623,27 @@ smb2_is_valid_lease_break(char *buffer)
607623
spin_lock(&tcon->open_file_lock);
608624
cifs_stats_inc(
609625
&tcon->stats.cifs_stats.num_oplock_brks);
610-
if (smb2_tcon_has_lease(tcon, rsp, lw)) {
626+
if (smb2_tcon_has_lease(tcon, rsp)) {
611627
spin_unlock(&tcon->open_file_lock);
612628
spin_unlock(&cifs_tcp_ses_lock);
613629
return true;
614630
}
631+
open = smb2_tcon_find_pending_open_lease(tcon,
632+
rsp);
633+
if (open) {
634+
__u8 lease_key[SMB2_LEASE_KEY_SIZE];
635+
struct tcon_link *tlink;
636+
637+
tlink = cifs_get_tlink(open->tlink);
638+
memcpy(lease_key, open->lease_key,
639+
SMB2_LEASE_KEY_SIZE);
640+
spin_unlock(&tcon->open_file_lock);
641+
spin_unlock(&cifs_tcp_ses_lock);
642+
smb2_queue_pending_open_break(tlink,
643+
lease_key,
644+
rsp->NewLeaseState);
645+
return true;
646+
}
615647
spin_unlock(&tcon->open_file_lock);
616648

617649
if (tcon->crfid.is_valid &&
@@ -629,7 +661,6 @@ smb2_is_valid_lease_break(char *buffer)
629661
}
630662
}
631663
spin_unlock(&cifs_tcp_ses_lock);
632-
kfree(lw);
633664
cifs_dbg(FYI, "Can not process lease break - no lease matched\n");
634665
return false;
635666
}

0 commit comments

Comments
 (0)