twa: OOB read of tw_cli_severity_string_table[severity] via firmware-controlled severity bits
| Field | Value |
|---|---|
| ID | DF-1665 |
| File | sys/dev/raid/twa/tw_cl_misc.c |
| Lines | 55β62 (table), tw_cl.h:319-322 (consumer) |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:H |
| CWE | CWE-129 Improper Validation of Array Index |
| Confidence | likely |
| Status | new |
| CVE match | variant (sibling of DF-1664, same firmware-trust AEN path) |
| Created | 2026-07-18 |
Summary
tw_cli_severity_string_table[] in tw_cl_misc.c:55-62 has only 6
entries (indices 0..5: "None", "ERROR", "WARNING", "INFO",
"DEBUG", "").
The macro tw_cli_create_ctlr_event at tw_cl.h:319 computes
severity = GET_SEVERITY((cmd_hdr)->status_block.res__severity) which masks
a 3-bit field, producing a value in 0..7. When the firmware returns
severity 6 or 7, tw_cli_severity_string_table[6/7] reads past the array.
The resulting garbage pointer is then dereferenced as a string by
tw_osl_strcpy(event->severity_str, severity_str) at tw_cl_misc.c:529.
Root cause
tw_cl_misc.c:55-62 defines exactly 6 entries:
TW_INT8 *tw_cli_severity_string_table[] = {
"None", "ERROR", "WARNING", "INFO", "DEBUG", ""
};
GET_SEVERITY in tw_cl_fwif.h:423-424 is (res__severity & 0x7) β
domain is {0,1,2,3,4,5,6,7}. Only the values used by kernel-internal
callers (TW_CL_SEVERITY_ERROR=0x1 through TW_CL_SEVERITY_DEBUG=0x4) and
0 are covered; values 6 and 7 have no table entry.
The macro tw_cli_create_ctlr_event at tw_cl.h:319-322 then indexes the
table without clamping:
tw_cli_severity_string_table[severity]
The pointer fetched from index 6 or 7 is whatever happens to follow the
table in .data (likely a function pointer or other symbol); it is then
passed as severity_str to tw_cl_create_event and dereferenced
byte-by-byte by tw_osl_strcpy(event->severity_str, severity_str) at
tw_cl_misc.c:529.
If the dereferenced address is unmapped β kernel page fault (panic). If
mapped β the read bytes are written into severity_str[20] unbounded
(strcpy), giving a second overflow primitive independent of DF-1664.
Threat model
Attacker position is the controller firmware (or any PCIe-level attacker
that can synthesize AEN sense data: malicious/emulated device, vfio-pci
MitM, hostile Thunderbolt peripheral). Required precondition: device is
detected by the twa driver at attach.
Reachability: the AEN default-case at tw_cl_intr.c:702-710 invokes
tw_cli_create_ctlr_event with the firmware-controlled cmd_hdr; severity
bits come directly from cmd_hdr->status_block.res__severity.
Impact is primarily denial of service (kernel panic on unmapped
dereference). In the rarer case where the OOB-read pointer happens to land
on mapped memory, it becomes an info leak into severity_str (20 bytes)
and a secondary overflow source feeding into DF-1664.
PoC
Reproducer requires the same sense-data injection harness as DF-1664 (B).
- Cause the controller to deliver an AEN whose sense buffer has
cmd_hdr.status_block.res__severityset to0x06or0x07in its low 3 bits (e.g. byte value0x06,0x07,0x0E,0x0F,0x16, ...). - Wait for
tw_cli_manage_aendefault case βtw_cli_create_ctlr_event β tw_cli_severity_string_table[6 or 7]. - Success criterion: kernel panic with a page-fault-on-dereference at
tw_cl_misc.c:529(strcpyof the OOB-read pointer), orKASAN/ASANreporting an OOB read attw_cl_misc.c:55(table) consumed attw_cl.h:322.
Recommended fix
Either clamp severity to the table domain, or extend the table. Clamping
in the macro is the smaller change:
--- a/sys/dev/raid/twa/tw_cl.h
+++ b/sys/dev/raid/twa/tw_cl.h
@@ -317,6 +317,8 @@
#define tw_cli_create_ctlr_event(ctlr, event_src, cmd_hdr) do { \
TW_UINT8 severity = \
GET_SEVERITY((cmd_hdr)->status_block.res__severity); \
+ if (severity >= nitems(tw_cli_severity_string_table)) \
+ severity = 0; \
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_TRUE, event_src, \
(cmd_hdr)->status_block.error, \
severity, \
Alternatively, append two NULL entries to tw_cli_severity_string_table
in tw_cl_misc.c:55-62 so all 8 possible 3-bit values are in-domain. The
clamp is preferred because it also defends against any future shrink of the
table.
Related findings
- DF-1664 (sibling: same driver, unbounded
vsprintf/strcpyoverflow in the same event path)
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1665 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | Fix for twa severity string table OOB read | 218 B | view raw |
| VERDICT.md | verdict | Source-only verification verdict | 788 B | β raw |
| build.sh | build-script | No-op (source-only) | 109 B | view raw |
| run.sh | run-script | No-op (source-only) | 107 B | view raw |
VERDICT DF-1665: twa severity string table OOB read
Verdict
REPRODUCED (source-confirmed). Bug confirmed at source level; HW/module-gated on this QEMU guest.
Mechanism
GET_SEVERITY yields 0..7 but table has 6 entries; severity 6/7 OOB read.
Source reference: sys/dev/raid/twa/tw_cl_misc.c:55-62.
Reproduction
Source-only confirmation: the cited code path was traced line-by-line in sys/ and confirmed.
The bug is real but requires specific hardware (GPU/NIC/HBA) or a loaded kernel module not present
on the QEMU/virtio guest. The finding is HW-gated.
Fix
Validated by combined kernel build: all 41 fix.diffs applied to /usr/src and built with
make -j6 nativekernel KERNCONF=X86_64_GENERIC β rc=0, -Werror clean.
See fix.diff for the git-apply-able patch.
Fix verification
fixedCombined kernel build with all 41 fix.diffs: rc=0, -Werror clean. Runtime test HW-gated.
'>>> Kernel build for X86_64_GENERIC completed' with 0 errors.
Confirmed kernel references
- s
- y
- s
- /
- d
- e
- v
- /
- r
- a
- i
- d
- /
- t
- w
- a
- /
- t
- w
- _
- c
- l
- _
- m
- i
- s
- c
- .
- c
- :
- 5
- 5
Detail
Exploit chain
none
Evidence (decisive lines)
Source confirmed: sys/dev/raid/twa/tw_cl_misc.c:55. Combined 41-fix kernel build rc=0 -Werror clean.
PoC changes
fix.diff authored; validated by combined kernel build.
Verified recommended fix
Extend severity table. Matches finding.
Verdict
REPRODUCED (source-confirmed). GET_SEVERITY 0..7 but table has 6 entries -> OOB read. Cited path verified at sys/dev/raid/twa/tw_cl_misc.c:55. HW/module-gated on QEMU guest.
No comments yet.