Missing lower-bound check on signed gpio_ddc_line index in acquire_i2c_hw_engine allows negative-index array read
| Field | Value |
|---|---|
| ID | DF-2089 |
| 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:N |
| CWE | CWE-129 Improper Validation of Array Index |
| File | sys/dev/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.c |
| Lines | 122-126 |
| Area | drm/amd |
| Confidence | speculative |
| Discovered | 2026-07-25 |
| Reported | pending |
| Known CVE | none |
| CVE match | dfly_specific |
Summary
acquire_i2c_hw_engine guards the per-line engine lookup only with
if (line < GPIO_DDC_LINE_COUNT) (i2caux_dce80.c:124). enum gpio_ddc_line
is a signed type (it defines GPIO_DDC_LINE_UNKNOWN = -1 at
gpio_types.h:207), so a returned UNKNOWN value satisfies -1 < 8 and
the subsequent i2caux->i2c_hw_engines[line] (line 126) becomes a
negative-index OOB read. No demonstrable impact in the current dce80
configuration because the aliased adjacent slot resolves to NULL and is
caught at line 130, but the bound is incorrect and fragile.
Root cause
i2caux_dce80.c:122enum gpio_ddc_line line = dal_ddc_get_line(ddc);βdal_ddc_get_line(gpio_service.c:566-570) returns(enum gpio_ddc_line)dal_gpio_get_enum(ddc->pin_data)andgpio->enis a rawuint32_t(gpio_base.c:122-126, set from an unvalidatedenparameter atgpio_base.c:252andhw_gpio.c:187), so it is not guaranteed to be a valid in-range enum value.i2caux_dce80.c:124if (line < GPIO_DDC_LINE_COUNT)performs a SIGNED comparison (the enum type holds-1) and omits the lower boundline >= 0/line != GPIO_DDC_LINE_UNKNOWN.i2caux_dce80.c:126engine = i2caux->i2c_hw_engines[line];indexes with the unchecked (possibly -1) value.
The identical missing-lower-bound pattern is present in all siblings
(dce110 i2caux_dce110.c:98) and in the shared helper
get_hw_supported_ddc_line (i2caux.c:287), so this is systemic.
Threat model & preconditions
- Attacker position: privileged local user (root) with the ability to load a crafted VBIOS connector table, or a developer triggering the path before GPIO assignment.
- Privileges gained or impact: none demonstrated.
- Required config or capabilities: a
struct ddcwhosehw_info.hw_supportedistrueyet whosepin_data->enmaps toGPIO_DDC_LINE_UNKNOWNor another out-of-range value when cast through the enum. - Reachability: plausible from a malformed/misprogrammed VBIOS connector table or a DDC handle used before its GPIO line is assigned.
Proof of concept
No working exploit β impact is not demonstrated. Under the current dce80
struct layout (i2caux.h:67-75: i2c_sw_engines[8] immediately precedes
i2c_hw_engines[8]), the read at index -1 aliases i2c_sw_engines[7],
which dce80's construct never writes, so engine resolves to NULL and
the function returns NULL at line 130 β benign. Reproducing a crash would
additionally require i2c_sw_engines[7] to hold a non-NULL stale/garbage
pointer, which dce80 does not produce. Filed as Info/hardening.
Impact
Defense-in-depth gap, no demonstrated privilege or availability impact
today. A future struct reordering, or a sibling that initializes
i2c_sw_engines[7], would turn this into a real OOB read.
Recommended fix
Add the missing lower bound so the signed UNKNOWN sentinel and any
negative value are rejected before indexing. GPIO_DDC_LINE_MIN is already
defined as GPIO_DDC_LINE_DDC1 (=0) at gpio_types.h:218.
--- a/sys/dev/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.c
+++ b/sys/dev/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.c
@@ -121,7 +121,8 @@ static struct i2c_engine *acquire_i2c_hw_engine(
if (ddc->hw_info.hw_supported) {
enum gpio_ddc_line line = dal_ddc_get_line(ddc);
- if (line < GPIO_DDC_LINE_COUNT) {
+ if (line >= GPIO_DDC_LINE_MIN &&
+ line < GPIO_DDC_LINE_COUNT) {
non_generic = true;
engine = i2caux->i2c_hw_engines[line];
}
The same one-line lower-bound guard should be applied to the siblings
(dce100/110/112/120 acquire_i2c_hw_engine) and to
get_hw_supported_ddc_line() in i2caux.c:287 for a complete fix; those
are outside this file.
References
sys/dev/drm/amd/display/dc/i2caux/i2caux.c:287β same missing bound in the shared helper.sys/dev/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c:98β same missing bound in the dce110 sibling.
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-2089 Β· 2 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | git-apply-able fix | 393 B | view raw |
| VERDICT.md | verdict | source-trace confirmation | 614 B | β raw |
DF-2089 β i2caux_dce80 missing lower bound on signed gpio_ddc_line
Verdict
REPRODUCED (source-only confirmation). Bug confirmed by source tracing.
Mechanism
acquire_i2c_hw_engine (i2caux_dce80.c:124) checks only line < GPIO_DDC_LINE_COUNT. enum gpio_ddc_line is signed (GPIO_DDC_LINE_UNKNOWN=-1). If dal_ddc_get_line returns -1, the check passes and i2c_hw_engines[-1] is an OOB read before the array.
Fix
Add line >= 0 to the bounds check: if (line >= 0 && line < GPIO_DDC_LINE_COUNT).
Batch-build status
Applied with all 24 other fixes; kernel + modules compiled rc=0, 0 errors, -Werror.
Fix verification
fixedAdded line>=0 lower bound; batch build rc=0.
Added line>=0 lower bound; batch build rc=0.
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
i2caux_dce80 line<GPIO_DDC_LINE_COUNT misses negative OOB.
Verified recommended fix
i2caux_dce80 line<GPIO_DDC_LINE_COUNT misses negative OOB.
Verdict
i2caux_dce80 line<GPIO_DDC_LINE_COUNT misses negative OOB.
No comments yet.