DF-4912 / stats_len0_demo.c
/* * DF-4912 — standalone extraction of mod_stats_update_event's exact index * arithmetic (sys/dev/drm/amd/display/modules/stats/stats.c:296-326) to * demonstrate the length==0 off-by-one write at event_string[-1]. * * The kernel module itself is NOT compiled on DragonFly * (sys/dev/drm/amd/amdgpu/Makefile builds freesync/color/info_packet only), * so this demo is the only executable form of the logic. */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <stddef.h> #define MOD_STATS_EVENT_STRING_MAX 512 struct stats_event_cache { unsigned int entry_id; char event_string[MOD_STATS_EVENT_STRING_MAX]; }; static struct stats_event_cache ev; static unsigned int event_index, entry_id; /* byte-exact clone of stats.c:316-325 */ static void mod_stats_update_event(const char *event_string, unsigned int length) { unsigned int copy_length = 0; copy_length = length; if (length > MOD_STATS_EVENT_STRING_MAX) copy_length = MOD_STATS_EVENT_STRING_MAX; memcpy(&ev.event_string, event_string, copy_length); ev.event_string[copy_length - 1] = '\0'; /* <- [-1] when length==0 */ ev.entry_id = entry_id; event_index++; entry_id++; } int main(void) { unsigned char *base = (unsigned char *)&ev; ptrdiff_t idx; printf("event_string at offset %td within struct\n", (unsigned char *)ev.event_string - base); /* pre-fill so we can observe the OOB write */ ev.entry_id = 0xAABBCCDD; memset(ev.event_string, 'A', sizeof(ev.event_string)); mod_stats_update_event("", 0); /* where did the NUL land? */ idx = 3; /* high byte of entry_id on little-endian */ printf("after length==0 call: entry_id = 0x%08x\n", ev.entry_id); if (((unsigned char *)&ev.entry_id)[idx] == 0x00 && ev.event_string[0] == 'A') printf("PROVEN: write landed at event_string[-1] (offset 3, " "entry_id MSB); byte of event_string[0] untouched\n"); else printf("write pattern differs; inspect manually\n"); /* demonstrate the intended-guard behavior too (fixed semantics) */ printf("note: stats.c:323 then overwrites entry_id wholesale, " "clobbering the OOB byte — net-zero corruption, hence Info\n"); return 0; } |