CVE-2022-49789
Severity CVSS v4.0:
Pending analysis
Type:
Unavailable / Other
Publication date:
01/05/2025
Last modified:
02/05/2025
Description
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
scsi: zfcp: Fix double free of FSF request when qdio send fails<br />
<br />
We used to use the wrong type of integer in &#39;zfcp_fsf_req_send()&#39; to cache<br />
the FSF request ID when sending a new FSF request. This is used in case the<br />
sending fails and we need to remove the request from our internal hash<br />
table again (so we don&#39;t keep an invalid reference and use it when we free<br />
the request again).<br />
<br />
In &#39;zfcp_fsf_req_send()&#39; we used to cache the ID as &#39;int&#39; (signed and 32<br />
bit wide), but the rest of the zfcp code (and the firmware specification)<br />
handles the ID as &#39;unsigned long&#39;/&#39;u64&#39; (unsigned and 64 bit wide [s390x<br />
ELF ABI]). For one this has the obvious problem that when the ID grows<br />
past 32 bit (this can happen reasonably fast) it is truncated to 32 bit<br />
when storing it in the cache variable and so doesn&#39;t match the original ID<br />
anymore. The second less obvious problem is that even when the original ID<br />
has not yet grown past 32 bit, as soon as the 32nd bit is set in the<br />
original ID (0x80000000 = 2&#39;147&#39;483&#39;648) we will have a mismatch when we<br />
cast it back to &#39;unsigned long&#39;. As the cached variable is of a signed<br />
type, the compiler will choose a sign-extending instruction to load the 32<br />
bit variable into a 64 bit register (e.g.: &#39;lgf %r11,188(%r15)&#39;). So once<br />
we pass the cached variable into &#39;zfcp_reqlist_find_rm()&#39; to remove the<br />
request again all the leading zeros will be flipped to ones to extend the<br />
sign and won&#39;t match the original ID anymore (this has been observed in<br />
practice).<br />
<br />
If we can&#39;t successfully remove the request from the hash table again after<br />
&#39;zfcp_qdio_send()&#39; fails (this happens regularly when zfcp cannot notify<br />
the adapter about new work because the adapter is already gone during<br />
e.g. a ChpID toggle) we will end up with a double free. We unconditionally<br />
free the request in the calling function when &#39;zfcp_fsf_req_send()&#39; fails,<br />
but because the request is still in the hash table we end up with a stale<br />
memory reference, and once the zfcp adapter is either reset during recovery<br />
or shutdown we end up freeing the same memory twice.<br />
<br />
The resulting stack traces vary depending on the kernel and have no direct<br />
correlation to the place where the bug occurs. Here are three examples that<br />
have been seen in practice:<br />
<br />
list_del corruption. next->prev should be 00000001b9d13800, but was 00000000dead4ead. (next=00000001bd131a00)<br />
------------[ cut here ]------------<br />
kernel BUG at lib/list_debug.c:62!<br />
monitor event: 0040 ilc:2 [#1] PREEMPT SMP<br />
Modules linked in: ...<br />
CPU: 9 PID: 1617 Comm: zfcperp0.0.1740 Kdump: loaded<br />
Hardware name: ...<br />
Krnl PSW : 0704d00180000000 00000003cbeea1f8 (__list_del_entry_valid+0x98/0x140)<br />
R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:1 PM:0 RI:0 EA:3<br />
Krnl GPRS: 00000000916d12f1 0000000080000000 000000000000006d 00000003cb665cd6<br />
0000000000000001 0000000000000000 0000000000000000 00000000d28d21e8<br />
00000000d3844000 00000380099efd28 00000001bd131a00 00000001b9d13800<br />
00000000d3290100 0000000000000000 00000003cbeea1f4 00000380099efc70<br />
Krnl Code: 00000003cbeea1e8: c020004f68a7 larl %r2,00000003cc8d7336<br />
00000003cbeea1ee: c0e50027fd65 brasl %r14,00000003cc3e9cb8<br />
#00000003cbeea1f4: af000000 mc 0,0<br />
>00000003cbeea1f8: c02000920440 larl %r2,00000003cd12aa78<br />
00000003cbeea1fe: c0e500289c25 brasl %r14,00000003cc3fda48<br />
00000003cbeea204: b9040043 lgr %r4,%r3<br />
00000003cbeea208: b9040051 lgr %r5,%r1<br />
00000003cbeea20c: b9040032 lgr %r3,%r2<br />
Call Trace:<br />
[] __list_del_entry_valid+0x98/0x140<br />
([] __list_del_entry_valid+0x94/0x140)<br />
[] zfcp_fsf_req_dismiss_all+0xde/0x150 [zfcp]<br />
[] zfcp_erp_strategy_do_action+0x160/0x280 [zfcp]<br />
---truncated---
Impact
References to Advisories, Solutions, and Tools
- https://git.kernel.org/stable/c/0954256e970ecf371b03a6c9af2cf91b9c4085ff
- https://git.kernel.org/stable/c/11edbdee4399401f533adda9bffe94567aa08b96
- https://git.kernel.org/stable/c/1bf8ed585501bb2dd0b5f67c824eab45adfbdccd
- https://git.kernel.org/stable/c/90a49a6b015fa439cd62e45121390284c125a91f
- https://git.kernel.org/stable/c/d2c7d8f58e9cde8ac8d1f75e9d66c2a813ffe0ab