⬢ DragonFlyBSD Kernel Audit
DF-3854 / harness.c
← back to finding ↓ download raw
/*
 * 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;
}