In the Linux kernel, the following vulnerability has been resolved:
ath10k: skip ath10k_halt during suspend for driver state RESTARTING
Double free crash is observed when FW recovery(caused by wmi timeout/crash) is followed by immediate suspend event. The FW recovery is triggered by ath10kcorerestart() which calls driver clean up via ath10khalt(). When the suspend event occurs between the FW recovery, the restart worker thread is put into frozen state until suspend completes. The suspend event triggers ath10kstop() which again triggers ath10khalt() The double invocation of ath10khalt() causes ath10khttrxfree() to be called twice(Note: ath10khttrxalloc was not called by restart worker thread because of its frozen state), causing the crash.
To fix this, during the suspend flow, skip call to ath10khalt() in ath10kstop() when the current driver state is ATH10KSTATERESTARTING. Also, for driver state ATH10KSTATERESTARTING, call ath10kwaitforsuspend() in ath10kstop(). This is because call to ath10kwaitforsuspend() is skipped later in [ath10khalt() > ath10kcorestop()] for the driver state ATH10KSTATERESTARTING.
The frozen restart worker thread will be cancelled during resume when the device comes out of suspend.
Below is the crash stack for reference:
[ 428.469167] ------------[ cut here ]------------ [ 428.469180] kernel BUG at mm/slub.c:4150! [ 428.469193] invalid opcode: 0000 [#1] PREEMPT SMP NOPTI [ 428.469219] Workqueue: eventsunbound asyncrunentryfn [ 428.469230] RIP: 0010:kfree+0x319/0x31b [ 428.469241] RSP: 0018:ffffa1fac015fc30 EFLAGS: 00010246 [ 428.469247] RAX: ffffedb10419d108 RBX: ffff8c05262b0000 [ 428.469252] RDX: ffff8c04a8c07000 RSI: 0000000000000000 [ 428.469256] RBP: ffffa1fac015fc78 R08: 0000000000000000 [ 428.469276] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 428.469285] Call Trace: [ 428.469295] ? dmafreeattrs+0x5f/0x7d [ 428.469320] ath10kcorestop+0x5b/0x6f [ 428.469336] ath10khalt+0x126/0x177 [ 428.469352] ath10kstop+0x41/0x7e [ 428.469387] drvstop+0x88/0x10e [ 428.469410] _ieee80211suspend+0x297/0x411 [ 428.469441] rdevsuspend+0x6e/0xd0 [ 428.469462] wiphysuspend+0xb1/0x105 [ 428.469483] ? nameshow+0x2d/0x2d [ 428.469490] dpmruncallback+0x8c/0x126 [ 428.469511] ? nameshow+0x2d/0x2d [ 428.469517] _devicesuspend+0x2e7/0x41b [ 428.469523] asyncsuspend+0x1f/0x93 [ 428.469529] asyncrunentryfn+0x3d/0xd1 [ 428.469535] processonework+0x1b1/0x329 [ 428.469541] workerthread+0x213/0x372 [ 428.469547] kthread+0x150/0x15f [ 428.469552] ? prcontwork+0x58/0x58 [ 428.469558] ? kthread_blkcg+0x31/0x31
Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00288-QCARMSWPZ-1