DF-3854 / harness.c
/* * DF-3854 harness — NULL-deref: RBIOS8(offset) executed BEFORE the * `if (offset)` guard in radeon_combios_external_tmds_setup. * * Kernel path (replicated 1:1): * sys/dev/drm/radeon/r100.c:4056-4059 * if (!radeon_get_bios(rdev)) { * if (ASIC_IS_AVIVO(rdev)) <- pre-AVIVO chips FALL THROUGH * return -EINVAL; * } * ... driver continues with rdev->bios == NULL on exactly the * combios-era (r100..rv4xx/rs4xx) chips this parser serves. * sys/dev/drm/radeon/radeon_combios.c:124-132 combios_get_table_offset(): * if (!rdev->bios) return 0; * sys/dev/drm/radeon/radeon_combios.c:2888-2891 * if (rdev->flags & RADEON_IS_IGP) { * offset = combios_get_table_offset(dev, COMBIOS_TMDS_POWER_ON_TABLE); * rev = RBIOS8(offset); <-- deref BEFORE the check * if (offset) { ... } * * With bios == NULL, offset == 0 and RBIOS8(0) is ((uint8_t*)NULL)[0]: * NULL page dereference -> kernel panic at the first external-TMDS modeset * (radeon_legacy_encoders.c:985). In userspace the identical expression * raises SIGSEGV. */ #include <stdio.h> #include <stdint.h> /* rdev->bios — NULL because radeon_get_bios() failed and r100_init() * deliberately continues for pre-AVIVO ASICs. */ static uint8_t *bios; /* = NULL */ #define RBIOS8(i) (bios[i]) /* radeon.h:2686 */ /* radeon_combios.c:124 combios_get_table_offset(COMBIOS_TMDS_POWER_ON_TABLE) */ static uint16_t combios_get_table_offset(void) { if (!bios) /* :131 */ return 0; return 0x1234; } int main(void) { uint16_t offset; uint8_t rev; printf("== DF-3854: IGP board, ROM unreadable -> rdev->bios == NULL ==\n"); printf("r100_init: pre-AVIVO, radeon_get_bios() failed, driver continues\n"); printf("radeon_combios_i2c_init / connector table fallback engaged; " "first ext-TMDS modeset reaches radeon_combios_external_tmds_setup()\n\n"); offset = combios_get_table_offset(); /* radeon_combios.c:2889 */ printf("combios_get_table_offset(TMDS_POWER_ON) = 0x%04x " "(NULL bios -> 0, radeon_combios.c:131)\n", offset); printf("executing radeon_combios.c:2890: rev = RBIOS8(offset); " "i.e. bios[%u] with bios == %p ...\n", offset, (void *)bios); fflush(stdout); rev = RBIOS8(offset); /* <-- the bug */ printf("unreachable: rev=%u\n", rev); return 0; } |