DF-2202 / df2202_trigger.c
/* * DF-2202 trigger stub โ amdgpu df_v1_7 OOB array index. * * This file is a STATIC ANALYSIS TRIGGER. It is not, and cannot be, a runtime * exploit: the vulnerable path lives inside the amdgpu DRM module which is * only reachable on Vega10 / Vega12 (CHIP_VEGA10 / CHIP_VEGA12) discrete GPU * hardware that this guest does not have. The function chain is: * * soc15.c:521-522 adev->df_funcs = &df_v1_7_funcs; // VEGA10/12 only * gmc_v9_0.c:812 numchan = adev->df_funcs->get_hbm_channel_number(adev); * * which calls * * df_v1_7.c:65 fb_channel_number = adev->df_funcs->get_fb_channel_number(adev); * df_v1_7.c:67 return df_v1_7_channel_number[fb_channel_number]; * * `get_fb_channel_number` masks a HW register field to a 4-bit value * (0..15) but the table has only 9 entries (indices 0..8). Values 9..15 * read 1..6 u32 words (4..24 bytes) past the end of the static array. * * The "trigger" is the act of initializing a Vega10/12 dGPU with an * IntLvNumChan register field holding 9..15 โ produced either by a malicious * VBIOS ROM (hotplugged PCIe card), a malicious hypervisor SR-IOV VF, or a * transient read during early bring-up. None of these can be reproduced on * this audit guest; verification is therefore source-only. * * This stub exists so a human reader of the evidence pack has a runnable * demonstration of the *indexing* bug in isolation. It does NOT touch kernel * memory; it builds as a userspace program and proves the table is OOB-exposed * to its full 4-bit input domain. */ #include <stdio.h> #include <stdint.h> /* * Verbatim copy of sys/dev/drm/amd/amdgpu/df_v1_7.c:30 (9 elements, 0..8). */ static const uint32_t df_v1_7_channel_number[] = {1, 2, 0, 4, 0, 8, 0, 16, 2}; #define TABLE_NENTRY (sizeof(df_v1_7_channel_number) / sizeof(df_v1_7_channel_number[0])) /* * Verbatim mask/shift from * sys/dev/drm/amd/include/asic_reg/df/df_1_7_sh_mask.h:39,44 */ #define DF_CS_AON0_DramBaseAddress0__IntLvNumChan__SHIFT 0x4 #define DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK 0x000000F0L /* Emulate df_v1_7_get_fb_channel_number(): register field decoded into index. */ static uint32_t df_v1_7_get_fb_channel_number(uint32_t hw_reg) { uint32_t tmp = hw_reg; tmp &= DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK; tmp >>= DF_CS_AON0_DramBaseAddress0__IntLvNumChan__SHIFT; return tmp; } int main(void) { printf("DF-2202 trigger stub โ amdgpu df_v1_7 OOB array index\n"); printf("table df_v1_7_channel_number[] has %zu entries (indices 0..%zu)\n", TABLE_NENTRY, TABLE_NENTRY - 1); printf("IntLvNumChan field is 4-bit -> values 0..15\n"); printf("\n"); int oob_count = 0; for (uint32_t reg = 0; reg < 0x10; reg++) { uint32_t idx = df_v1_7_get_fb_channel_number(reg << DF_CS_AON0_DramBaseAddress0__IntLvNumChan__SHIFT); const char *where = (idx < TABLE_NENTRY) ? "IN-BOUNDS" : "OOB"; if (idx >= TABLE_NENTRY) { size_t off_words = idx - TABLE_NENTRY; /* 0..6 */ size_t off_bytes = off_words * sizeof(uint32_t); /* 0..24 */ oob_count++; printf(" field=%2u -> INDEX %2u %s (u32 read at offset %zu word(s) = %zu byte(s) past end)\n", idx, idx, where, off_words, off_bytes); } else { printf(" field=%2u -> INDEX %2u %s value=%u\n", idx, idx, where, df_v1_7_channel_number[idx]); } } printf("\n"); printf("%d of 16 possible field values land OUT-OF-BOUNDS on the table.\n", oob_count); printf("OOB reads land at offset 0..6 u32 words (0..24 bytes) past the end\n"); printf("of the static array, reading whatever 4-byte word lives there.\n"); return 0; } |