ar5416GpioGet reads wrong GPIO input bit on AR9287 (KIWI) due to missing else
| Field | Value |
|---|---|
| ID | DF-2099 |
| Status | new |
| Severity | Info |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:L |
| CWE | CWE-670 Control Flow Implementation of Extra Step; CWE-480 Use of Incorrect Operator |
| File | sys/dev/netif/ath/ath_hal/ar5416/ar5416_gpio.c |
| Lines | 192-200 |
| Area | net/ath |
| Confidence | certain |
| Discovered | 2026-07-25 |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
In ar5416GpioGet the chip-revision dispatch chain is broken: line 194
uses if instead of else if. Because
AR_XSREV_VERSION_KIWI (0x180) is numerically >= AR_XSREV_VERSION_KITE
(0xC0), any KIWI (AR9287) chip passes both AR_SREV_KIWI_10_OR_LATER
and AR_SREV_KITE_10_OR_LATER, so the correct AR9287_GPIO_IN_VAL
extraction is immediately overwritten with the AR9285_GPIO_IN_VAL
mask/shift. ar5416GpioGet therefore returns the wrong input bit on
AR9287 hardware. No security boundary is crossed (GPIO input state on a
wifi NIC is not a privilege/security surface); reported as a reproducible
correctness defect in the audited file.
Root cause
ar5416_gpio.c:192-199:
if (AR_SREV_KIWI_10_OR_LATER(ah)) // macVersion >= 0x180
bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9287_GPIO_IN_VAL);
if (AR_SREV_KITE_10_OR_LATER(ah)) // <-- BUG: 'if', not 'else if'
bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9285_GPIO_IN_VAL);
else if (AR_SREV_MERLIN_10_OR_LATER(ah))
bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR928X_GPIO_IN_VAL);
else
bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL);
The macros (ar5416reg.h:740,757,785) are simple >= version comparisons,
so a KIWI chip (0x180) satisfies KITE_10_OR_LATER (>=0xC0) and
MERLIN_10_OR_LATER (>=0x80). The second if executes unconditionally
after the KIWI branch and overwrites bits with
MS(reg, AR9285_GPIO_IN_VAL) (mask 0x00FFF000, shift 12,
ar5416reg.h:565-566) instead of the correct AR9287 mask
(0x003FF800, shift 11, ar5416reg.h:567-568). The final
return ((bits & AR_GPIO_BIT(gpio)) != 0) (ar5416_gpio.c:200) thus
tests a different bit position than intended on AR9287.
Threat model & preconditions
- Attacker position: N/A β functional correctness defect.
- Privileges gained or impact: none β on AR9287 (KIWI) NICs, callers
of
ath_hal_gpioget(wrapped atif_athvar.h:1468) observe a GPIO input bit taken from the wrong field ofAR_GPIO_IN_OUT. Worst case: a misread hardware GPIO input (e.g. an external signal sampled via the NIC GPIO header) is interpreted incorrectly. - Required config or capabilities: AR9287 (KIWI) hardware.
- Reachability:
ar5416GpioGetappears to have no in-tree caller in theath(4)driver itself today, further limiting impact to out-of-tree/HAL-tool consumers.
Proof of concept
Not a security exploit; included for completeness and reproducibility. On
AR9287 hardware, call ath_hal_gpioget(ah, n) for any pin n in
[0, halNumGpioPins) and compare against the datasheet value of
AR_GPIO_IN_OUT[11..21] (AR9287_GPIO_IN_VAL). The returned bit will
instead reflect AR_GPIO_IN_OUT[12..23] (AR9285 layout). A unit-style
check: read AR_GPIO_IN_OUT once, manually extract
(val & 0x003FF800) >> 11, and diff against the function's return for
each pin; mismatch on AR9287 confirms the bug.
Impact
Functional correctness only. No panic, no leak.
Recommended fix
Change the if at ar5416_gpio.c:194 to else if so the dispatch is
mutually exclusive:
--- a/sys/dev/netif/ath/ath_hal/ar5416/ar5416_gpio.c
+++ b/sys/dev/netif/ath/ath_hal/ar5416/ar5416_gpio.c
@@ -192,7 +192,7 @@ ar5416GpioGet(struct ath_hal *ah, uint32_t gpio)
*/
if (AR_SREV_KIWI_10_OR_LATER(ah))
bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9287_GPIO_IN_VAL);
- if (AR_SREV_KITE_10_OR_LATER(ah))
+ else if (AR_SREV_KITE_10_OR_LATER(ah))
bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9285_GPIO_IN_VAL);
else if (AR_SREV_MERLIN_10_OR_LATER(ah))
bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR928X_GPIO_IN_VAL);
References
sys/dev/netif/ath/ath_hal/ar5416/ar5416reg.h:565-568,740,757,785β the macro definitions that make the dispatch non-exclusive.
Timeline
- 2026-07-25 Discovered during automated audit.
- 2026-07-25 Reported to DragonFlyBSD security contact.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2099 Β· 2 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | git-apply-able fix | 1.5 KB | view raw |
| VERDICT.md | verdict | source-trace confirmation | 579 B | β raw |
DF-2099 β ar5416GpioGet wrong GPIO bit on AR9287 (KIWI)
Verdict
REPRODUCED (source-only confirmation). Bug confirmed by source tracing.
Mechanism
ar5416GpioGet (ar5416_gpio.c:192-195): line 194 uses 'if' not 'else if'. AR_XSREV_VERSION_KIWI(0x180) >= AR_XSREV_VERSION_KITE(0xC0), so KIWI chips pass both checks: line 193 sets correct AR9287_GPIO_IN_VAL, then line 194 overwrites with wrong AR9285_GPIO_IN_VAL.
Fix
Change 'if' to 'else if' at line 194.
Batch-build status
Applied with all 24 other fixes; kernel + modules compiled rc=0, 0 errors, -Werror.
Fix verification
fixedChanged if to else if; batch build rc=0.
Changed if to else if; batch build rc=0.
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
ar5416GpioGet uses if not else if; AR9287 overwrites wrong field.
Verified recommended fix
ar5416GpioGet uses if not else if; AR9287 overwrites wrong field.
Verdict
ar5416GpioGet uses if not else if; AR9287 overwrites wrong field.
No comments yet.