In the Linux kernel, the following vulnerability has been resolved:
smb: client: fix use-after-free in smb2queryinfo_compound()
The following UAF was triggered when running fstests generic/072 with KASAN enabled against Windows Server 2022 and mount options 'multichannel,max_channels=2,vers=3.1.1,mfsymlinks,noperm'
BUG: KASAN: slab-use-after-free in smb2queryinfocompound+0x423/0x6d0 [cifs] Read of size 8 at addr ffff888014941048 by task xfsio/27534
CPU: 0 PID: 27534 Comm: xfsio Not tainted 6.6.0-rc7 #1 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.2-3-gd478f380-rebuilt.opensuse.org 04/01/2014 Call Trace: dumpstacklvl+0x4a/0x80 printreport+0xcf/0x650 ? srsoaliasreturnthunk+0x5/0x7f ? srsoaliasreturnthunk+0x5/0x7f ? physaddr+0x46/0x90 kasanreport+0xda/0x110 ? smb2queryinfocompound+0x423/0x6d0 [cifs] ? smb2queryinfocompound+0x423/0x6d0 [cifs] smb2queryinfocompound+0x423/0x6d0 [cifs] ? _pfxsmb2queryinfocompound+0x10/0x10 [cifs] ? srsoaliasreturnthunk+0x5/0x7f ? _stackdepotsave+0x39/0x480 ? kasansavestack+0x33/0x60 ? kasansettrack+0x25/0x30 ? kasanslabfree+0x126/0x170 smb2queryfs+0xc2/0x2c0 [cifs] ? pfxsmb2queryfs+0x10/0x10 [cifs] ? _pfxlockacquire+0x10/0x10 smb311queryfs+0x210/0x220 [cifs] ? pfxsmb311queryfs+0x10/0x10 [cifs] ? srsoaliasreturnthunk+0x5/0x7f ? _lockacquire+0x480/0x26c0 ? lockrelease+0x1ed/0x640 ? srsoaliasreturnthunk+0x5/0x7f ? dorawspinunlock+0x9b/0x100 cifsstatfs+0x18c/0x4b0 [cifs] statfsbydentry+0x9b/0xf0 fdstatfs+0x4e/0xb0 _dosysfstatfs+0x7f/0xe0 ? _pfxdosysfstatfs+0x10/0x10 ? srsoaliasreturnthunk+0x5/0x7f ? lockdephardirqsonprepare+0x136/0x200 ? srsoaliasreturnthunk+0x5/0x7f dosyscall64+0x3f/0x90 entrySYSCALL64after_hwframe+0x6e/0xd8
Allocated by task 27534: kasansavestack+0x33/0x60 kasansettrack+0x25/0x30 _kasankmalloc+0x8f/0xa0 opencacheddir+0x71b/0x1240 [cifs] smb2queryinfocompound+0x5c3/0x6d0 [cifs] smb2queryfs+0xc2/0x2c0 [cifs] smb311queryfs+0x210/0x220 [cifs] cifsstatfs+0x18c/0x4b0 [cifs] statfsbydentry+0x9b/0xf0 fdstatfs+0x4e/0xb0 _dosysfstatfs+0x7f/0xe0 dosyscall64+0x3f/0x90 entrySYSCALL64afterhwframe+0x6e/0xd8
Freed by task 27534: kasansavestack+0x33/0x60 kasansettrack+0x25/0x30 kasansavefreeinfo+0x2b/0x50 __kasanslabfree+0x126/0x170 slabfreefreelisthook+0xd0/0x1e0 _kmemcachefree+0x9d/0x1b0 opencacheddir+0xff5/0x1240 [cifs] smb2queryinfocompound+0x5c3/0x6d0 [cifs] smb2_queryfs+0xc2/0x2c0 [cifs]
This is a race between opencacheddir() and cacheddirleasebreak() where the cache entry for the open directory handle receives a lease break while creating it. And before returning from opencacheddir(), we put the last reference of the new @cfid because of !@cfid->haslease.
Besides the UAF, while running xfstests a lot of missed lease breaks have been noticed in tests that run several concurrent statfs(2) calls on those cached fids
CIFS: VFS: \w22-root1.gandalf.test No task to wake, unknown frame... CIFS: VFS: \w22-root1.gandalf.test Cmd: 18 Err: 0x0 Flags: 0x1... CIFS: VFS: \w22-root1.gandalf.test smb buf 00000000715bfe83 len 108 CIFS: VFS: Dump pending requests: CIFS: VFS: \w22-root1.gandalf.test No task to wake, unknown frame... CIFS: VFS: \w22-root1.gandalf.test Cmd: 18 Err: 0x0 Flags: 0x1... CIFS: VFS: \w22-root1.gandalf.test smb buf 000000005aa7316e len 108 ...
To fix both, in opencacheddir() ensure that @cfid->haslease is set right before sending out compounded request so that any potential lease break will be get processed by demultiplex thread while we're still caching @cfid. And, if open failed for some reason, re-check @cfid->haslease to decide whether or not put lease reference.