DF-1818 / harness.c
/* * DF-1818 source-confirmation harness (fill_rect24 slow path over-advances). * * sys/dev/misc/syscons/sckmsrndr.c:437-446 slow path: * for (i = 0; i < height; i++) { * for (j = 0; j < width; j++) { writeb(3 bytes); draw_pos += 3; } // +3*width * draw_pos += line_width; // BUG: should be += d * } * where d = line_width - width*3 is the per-row right-padding (line 420). * The fast path (423-436) correctly does draw_pos += d at line 435. * Slow path is taken when (draw_pos|line_width|width) & 3 != 0, e.g. * 1366x768@24bpp right border (width=6, 6&3=2). Drift per row = * (height-1)*3*width. This harness reproduces the arithmetic. * * Build: cc -O2 -o harness harness.c * Run: ./harness */ #include <stdio.h> #include <stdlib.h> #include <string.h> /* Model of the framebuffer: vaddr + stride*height bytes. */ static unsigned char *fb; static size_t fb_size; static size_t write_count; static void writeb_model(size_t pos, unsigned char v) { if (pos < fb_size) { fb[pos] = v; write_count++; } /* else: OOB — in the kernel this is an unchecked volatile store */ } /* Verbatim slow-path logic from sckmsrndr.c:437-446. */ static size_t fill_rect24_slow(size_t draw_pos, int width, int height, int line_width) { for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { writeb_model(draw_pos, 0xAA); writeb_model(draw_pos + 1, 0xBB); writeb_model(draw_pos + 2, 0xCC); draw_pos += 3; } draw_pos += line_width; /* BUG (sckmsrndr.c:445) — should be += d */ } return draw_pos; } /* Fixed slow-path: draw_pos += d (= line_width - width*3). */ static size_t fill_rect24_slow_fixed(size_t draw_pos, int width, int height, int line_width) { int d = line_width - width * 3; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { writeb_model(draw_pos, 0xAA); writeb_model(draw_pos + 1, 0xBB); writeb_model(draw_pos + 2, 0xCC); draw_pos += 3; } draw_pos += d; /* FIXED */ } return draw_pos; } int main(void) { /* 1366x768@24bpp, stride = 1366*3 = 4098, but rounds up to 4096+? use 4096 stride * The right border: width = 1366 - xsize*blk_width. With scp->xsize=170 (default * 80-col*8px*... approx) the right border is small. Use the finding's worked eg: * rightpixel=6, height=768, line_width=4096. */ int line_width = 4096, width = 6, height = 768; size_t vaddr = 0; fb_size = (size_t)line_width * 768; fb = calloc(1, fb_size + 8192); /* give headroom so we can SEE the overrun */ write_count = 0; size_t end_bug = fill_rect24_slow(vaddr, width, height, line_width); size_t inbounds_bug = (end_bug + 2 < fb_size) ? end_bug : fb_size; /* number of bytes the slow path wrote PAST the framebuffer mapping */ long overflow_bug = (long)end_bug - (long)fb_size; /* Reset and run the FIXED version */ memset(fb, 0, fb_size + 8192); write_count = 0; size_t end_fix = fill_rect24_slow_fixed(vaddr, width, height, line_width); long overflow_fix = (long)end_fix - (long)fb_size; printf("DF-1818: fill_rect24 slow path (sckmsrndr.c:437-446)\n"); printf(" width=%d height=%d line_width=%d d=%d (per-row padding)\n", width, height, line_width, line_width - width*3); printf(" BUGGY (+=line_width at :445): final draw_pos=%zu, %ld bytes PAST fb end\n", end_bug, overflow_bug); printf(" FIXED (+=d): final draw_pos=%zu, %ld bytes past fb end\n", end_fix, overflow_fix); printf(" Per-row drift = 3*width = %d bytes; total drift = (height-1)*3*width = %d bytes\n", 3*width, (height-1)*3*width); free(fb); return 0; } |