From a91572dd049386ec2b8545bbe1c0aeb0be2d2980 Mon Sep 17 00:00:00 2001 From: Chris Atkin Date: Mon, 27 Apr 2026 20:46:18 +0100 Subject: [PATCH] video/drm: bmp_helper: fix out-of-bounds write in RLE8 DELTA decoder decode_rle8_bitmap() handles the BMP RLE8 DELTA escape without bounds checking x or y before adjusting the destination pointer. In flip mode (positive BMP height), y starts at height-1 and a single DELTA can drive it negative. Subsequent encoded and unencoded run bounds checks fail to reject negative y (signed comparison), so the decoder continues writing through an underflowed dst pointer. An attacker who controls the BMP colour table has full 16-bit value control per write position and can chain multiple DELTAs to reach arbitrary memory below the decode buffer. Fix four sites in decode_rle8_bitmap: 1. DELTA: validate x and y after adjustment, abort if out of bounds, and recompute dst from the base pointer pdst rather than adjusting it incrementally. 2. EOL: check y after decrement/increment and abort if it leaves the image. Recompute dst from pdst for the same reason. 3. Encoded runs: change "if (y < height)" to "if (y >= 0 && y < height)" so negative y is rejected. 4. Unencoded runs: add "y < 0" to the existing bounds check so negative y is rejected. --- drivers/video/drm/bmp_helper.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/video/drm/bmp_helper.c b/drivers/video/drm/bmp_helper.c index c387a02f9ed..a5999c59ebc 100755 --- a/drivers/video/drm/bmp_helper.c +++ b/drivers/video/drm/bmp_helper.c @@ -77,6 +77,8 @@ static void decode_rle8_bitmap(void *psrc, void *pdst, uint16_t *cmap, } else { y++; } + if (y < 0 || y >= height) + decode = 0; break; case BMP_RLE8_EOBMP: /* end of bitmap */ @@ -95,12 +97,14 @@ static void decode_rle8_bitmap(void *psrc, void *pdst, uint16_t *cmap, dst += bmap[2] * 2; } bmap += 4; + if (x >= width || y < 0 || y >= height) + decode = 0; break; default: /* unencoded run */ runlen = bmap[1]; bmap += 2; - if (y >= height || x >= width) { + if (y < 0 || y >= height || x >= width) { decode = 0; break; } @@ -117,7 +121,7 @@ static void decode_rle8_bitmap(void *psrc, void *pdst, uint16_t *cmap, } } else { /* encoded run */ - if (y < height) { + if (y >= 0 && y < height) { runlen = bmap[0]; if (x < width) { /* aggregate the same code */