From: Ronnie Sahlberg lsahlber@redhat.com
mainline inclusion from mainline-v5.1-rc1 commit 0ff2b018b02f89da26a616e0148582321a00fd99 category: bugfix bugzilla: 1702264 CVE: NA
-------------------------------------------------
We need to protect so that the call to smb2_reconnect() in smb2_reconnect_server() does not end up freeing the session because it can lead to a use after free and crash.
[ 397.787693] CIFS VFS: cifs_mount failed w/return code = -2 [ 403.671998] BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 [ 403.672065] PGD 0 P4D 0 [ 403.672087] Oops: 0000 [#1] SMP PTI [ 403.672114] CPU: 3 PID: 47 Comm: kworker/3:1 Kdump: loaded Not tainted 4.19.90-2003.1.1.0033.oe1.x86_64 #1 [ 403.672173] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.10.2-0-g5f4c7b1-20181220_000000-szxrtosci10000 04/01/2014 [ 403.673038] Workqueue: cifsiod smb2_reconnect_server [cifs] [ 403.673746] RIP: 0010:__list_del_entry_valid+0x25/0x90 [ 403.674448] Code: c3 0f 1f 40 00 48 8b 07 48 b9 00 01 00 00 00 00 ad de 48 8b 57 08 48 39 c8 74 26 48 b9 00 02 00 00 00 00 ad de 48 39 ca 74 2e <48> 8b 32 48 39 fe 75 3a 48 8b 50 08 48 39 f2 75 48 b8 01 00 00 00 [ 403.675955] RSP: 0018:ffffbd48007c3e18 EFLAGS: 00010207 [ 403.676696] RAX: 0000000000000000 RBX: ffffbd48007c3e50 RCX: dead000000000200 [ 403.677447] RDX: 0000000000000000 RSI: 0000000000000206 RDI: ffff9bee27f65818 [ 403.678214] RBP: ffffbd48007c3e38 R08: ffff9bee3bba3038 R09: 00000000000002c2 [ 403.679001] R10: ffffbd48006a3d90 R11: 0000000000000000 R12: ffff9bee27f66818 [ 403.679811] R13: 0000000000000001 R14: ffff9bee27f65800 R15: ffff9bee27f65818 [ 403.680639] FS: 0000000000000000(0000) GS:ffff9bee3bb80000(0000) knlGS:0000000000000000 [ 403.681505] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 403.682391] CR2: 0000000000000000 CR3: 000000003040a005 CR4: 00000000003606e0 [ 403.683315] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 403.684247] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 403.685181] Call Trace: [ 403.686141] smb2_reconnect_server+0x17a/0x340 [cifs] [ 403.687118] process_one_work+0x195/0x3d0 [ 403.688102] worker_thread+0x30/0x390 [ 403.689096] ? process_one_work+0x3d0/0x3d0 [ 403.690111] kthread+0x113/0x130 [ 403.691132] ? kthread_create_worker_on_cpu+0x70/0x70 [ 403.692181] ret_from_fork+0x35/0x40
Reviewed-by: Aurelien Aptel aaptel@suse.com Cc: stable@vger.kernel.org Signed-off-by: Ronnie Sahlberg lsahlber@redhat.com Signed-off-by: Steve French stfrench@microsoft.com Reviewed-by: Pavel Shilovsky pshilov@microsoft.com Signed-off-by: Feilong Lin linfeilong@huawei.com --- fs/cifs/cifsproto.h | 2 ++ fs/cifs/connect.c | 3 +-- fs/cifs/smb2pdu.c | 10 +++++++++- 3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index d7ac75e..bd97f2a 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -526,6 +526,8 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16, extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24);
+extern void cifs_put_smb_ses(struct cifs_ses *ses); + void cifs_readdata_release(struct kref *refcount); int cifs_async_readv(struct cifs_readdata *rdata); int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 7e85070..2e46a8a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2732,8 +2732,7 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) return NULL; }
-static void -cifs_put_smb_ses(struct cifs_ses *ses) +void cifs_put_smb_ses(struct cifs_ses *ses) { unsigned int rc, xid; struct TCP_Server_Info *server = ses->server; diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 30417d4..97995b2 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2914,9 +2914,14 @@ void smb2_reconnect_server(struct work_struct *work) tcon_exist = true; } } + /* + * IPC has the same lifetime as its session and uses its + * refcount. + */ if (ses->tcon_ipc && ses->tcon_ipc->need_reconnect) { list_add_tail(&ses->tcon_ipc->rlist, &tmp_list); tcon_exist = true; + ses->ses_count++; } } /* @@ -2935,7 +2940,10 @@ void smb2_reconnect_server(struct work_struct *work) else resched = true; list_del_init(&tcon->rlist); - cifs_put_tcon(tcon); + if (tcon->ipc) + cifs_put_smb_ses(tcon->ses); + else + cifs_put_tcon(tcon); }
cifs_dbg(FYI, "Reconnecting tcons finished\n");