summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShahriyar Jalayeri <[email protected]>2026-07-29 18:47:01 +0200
committerTom Rini <[email protected]>2026-08-26 16:33:21 -0600
commit5201e83342d64c2f438ea35158575f28225e752e (patch)
tree2ed0793c77e34b39f3b874c88920edbd8fa3570a
parentfdfe2ec48d5c1c2ed03073d73edd3fdd3fe1ffa1 (diff)
video: bmp: bound RLE8 decode writes to the framebuffer
video_display_rle8_bitmap() moves the framebuffer cursor fb up by a full row plus a scanline on each End-Of-Line escape, with no lower-bound check. Repeated EOL escapes desynchronise fb from the scanline index y: after height - 1 escapes y is back in range while fb has drifted about one framebuffer below priv->fb, and the decoder writes pixel data before the start of the framebuffer. The DELTA escape recomputes fb from an unchecked y as well. A crafted RLE8 image displayed from the splash-screen or PXE-menu path can therefore write out of bounds. Check the cursor against [priv->fb, priv->fb + fb_size) before each run and reject the image with -EINVAL if a write would fall outside it. Signed-off-by: Shahriyar Jalayeri <[email protected]> Reviewed-by: Simon Glass <[email protected]>
-rw-r--r--drivers/video/video_bmp.c28
1 files changed, 21 insertions, 7 deletions
diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c
index 1f267d45812..c6710f898da 100644
--- a/drivers/video/video_bmp.c
+++ b/drivers/video/video_bmp.c
@@ -122,13 +122,15 @@ static void draw_encoded_bitmap(u8 **fbp, uint bpix, enum video_format eformat,
*fbp = fb;
}
-static void video_display_rle8_bitmap(struct udevice *dev,
- struct bmp_image *bmp, uint bpix,
- struct bmp_color_table_entry *palette,
- uchar *fb, int x_off, int y_off,
- ulong width, ulong height)
+static int video_display_rle8_bitmap(struct udevice *dev,
+ struct bmp_image *bmp, uint bpix,
+ struct bmp_color_table_entry *palette,
+ uchar *fb, int x_off, int y_off,
+ ulong width, ulong height)
{
struct video_priv *priv = dev_get_uclass_priv(dev);
+ uchar *fb_start = priv->fb;
+ uchar *fb_end = (uchar *)priv->fb + priv->fb_size;
uchar *bmap;
ulong cnt, runlen;
int x, y;
@@ -176,6 +178,9 @@ static void video_display_rle8_bitmap(struct udevice *dev,
cnt = width - x;
else
cnt = runlen;
+ if (fb < fb_start ||
+ fb + cnt * bytes_per_pixel > fb_end)
+ return -EINVAL;
draw_unencoded_bitmap(
&fb, bpix, eformat,
bmap, palette, cnt);
@@ -202,6 +207,9 @@ static void video_display_rle8_bitmap(struct udevice *dev,
cnt = width - x;
else
cnt = runlen;
+ if (fb < fb_start ||
+ fb + cnt * bytes_per_pixel > fb_end)
+ return -EINVAL;
draw_encoded_bitmap(&fb, bpix, eformat,
palette, &bmap[1],
cnt);
@@ -211,6 +219,8 @@ static void video_display_rle8_bitmap(struct udevice *dev,
bmap += 2;
}
}
+
+ return 0;
}
/**
@@ -267,6 +277,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
enum video_format eformat;
struct bmp_color_table_entry *palette;
int hdr_size;
+ int ret;
if (!bmp || !(bmp->header.signature[0] == 'B' &&
bmp->header.signature[1] == 'M')) {
@@ -337,8 +348,11 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
&bmp->header.compression);
debug("compressed %d %d\n", compression, BMP_BI_RLE8);
if (compression == BMP_BI_RLE8) {
- video_display_rle8_bitmap(dev, bmp, bpix, palette, fb,
- x, y, width, height);
+ ret = video_display_rle8_bitmap(dev, bmp, bpix,
+ palette, fb, x, y,
+ width, height);
+ if (ret)
+ return ret;
break;
}
}