β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-1665

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).

  1. Cause the controller to deliver an AEN whose sense buffer has cmd_hdr.status_block.res__severity set to 0x06 or 0x07 in its low 3 bits (e.g. byte value 0x06, 0x07, 0x0E, 0x0F, 0x16, ...).
  2. Wait for tw_cli_manage_aen default case β†’ tw_cli_create_ctlr_event β†’ tw_cli_severity_string_table[6 or 7].
  3. Success criterion: kernel panic with a page-fault-on-dereference at tw_cl_misc.c:529 (strcpy of the OOB-read pointer), or KASAN/ASAN reporting an OOB read at tw_cl_misc.c:55 (table) consumed at tw_cl.h:322.

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.

  • DF-1664 (sibling: same driver, unbounded vsprintf/strcpy overflow in the same event path)

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1665 Β· 4 files
FileTypeDescriptionSize
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.md verdict Source-only verification verdict
↓ download 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

fixed
baseline reproduced→ patch + rebuild →patched clean

Combined 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.
↓ fix.diffDragonFly 6.5-DEVELOPMENT #0 master DEV (41 fix.diffs applied)

Confirmed kernel references

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.