From bf119fbee4ccebc6a67e7fe92e13d289c722f7e5 Mon Sep 17 00:00:00 2001 From: cepetr Date: Mon, 3 Mar 2025 16:33:10 +0100 Subject: [PATCH] feat(core): improve display/dma2d syscall verifiers [no changelog] --- core/embed/gfx/bitblt/stm32/dma2d_bitblt.c | 56 +++++++++++++++++++ core/embed/gfx/inc/gfx/gfx_bitblt.h | 21 +++++++ .../io/display/ltdc_dsi/display_fb_rgb565.c | 17 ++++++ .../io/display/ltdc_dsi/display_fb_rgb888.c | 17 ++++++ core/embed/io/display/st-7789/display_fb.c | 17 ++++++ core/embed/io/display/st-7789/display_nofb.c | 33 +++++++++++ .../display/stm32f429i-disc1/display_driver.c | 17 ++++++ .../embed/io/display/vg-2864/display_driver.c | 11 ++++ core/embed/sys/mpu/stm32u5/mpu.c | 1 + 9 files changed, 190 insertions(+) diff --git a/core/embed/gfx/bitblt/stm32/dma2d_bitblt.c b/core/embed/gfx/bitblt/stm32/dma2d_bitblt.c index 5f562d5f50..d2ff25fb34 100644 --- a/core/embed/gfx/bitblt/stm32/dma2d_bitblt.c +++ b/core/embed/gfx/bitblt/stm32/dma2d_bitblt.c @@ -109,6 +109,10 @@ bool dma2d_rgb565_fill(const gfx_bitblt_t* bb) { return false; } + if (!gfx_bitblt_check_dst_x(bb, 16)) { + return false; + } + dma2d_wait(); if (!dma2d_accessible(bb->dst_row)) { @@ -233,6 +237,11 @@ bool dma2d_rgb565_copy_mono4(const gfx_bitblt_t* params) { return false; } + if (!gfx_bitblt_check_dst_x(params, 16) || + !gfx_bitblt_check_src_x(params, 4)) { + return false; + } + const gfx_color16_t* src_gradient = NULL; gfx_bitblt_t bb_copy = *params; @@ -291,6 +300,10 @@ bool dma2d_rgb565_copy_rgb565(const gfx_bitblt_t* bb) { return false; } + if (!gfx_bitblt_check_dst_x(bb, 16) || !gfx_bitblt_check_src_x(bb, 16)) { + return false; + } + dma2d_wait(); if (!dma2d_accessible(bb->dst_row) || !dma2d_accessible(bb->src_row)) { @@ -355,6 +368,11 @@ bool dma2d_rgb565_blend_mono4(const gfx_bitblt_t* params) { return false; } + if (!gfx_bitblt_check_dst_x(params, 16) || + !gfx_bitblt_check_src_x(params, 4)) { + return false; + } + dma2d_wait(); gfx_bitblt_t bb_copy = *params; @@ -421,6 +439,10 @@ bool dma2d_rgb565_blend_mono8(const gfx_bitblt_t* bb) { return false; } + if (!gfx_bitblt_check_dst_x(bb, 16) || !gfx_bitblt_check_src_x(bb, 8)) { + return false; + } + dma2d_wait(); if (!dma2d_accessible(bb->dst_row) || !dma2d_accessible(bb->src_row)) { @@ -460,6 +482,10 @@ bool dma2d_rgba8888_fill(const gfx_bitblt_t* bb) { return false; } + if (!gfx_bitblt_check_dst_x(bb, 32)) { + return false; + } + dma2d_wait(); if (!dma2d_accessible(bb->dst_row)) { @@ -547,6 +573,11 @@ bool dma2d_rgba8888_copy_mono4(const gfx_bitblt_t* params) { return false; } + if (!gfx_bitblt_check_dst_x(params, 32) || + !gfx_bitblt_check_src_x(params, 4)) { + return false; + } + dma2d_wait(); const gfx_color32_t* src_gradient = NULL; @@ -606,6 +637,10 @@ bool dma2d_rgba8888_copy_rgb565(const gfx_bitblt_t* bb) { return false; } + if (!gfx_bitblt_check_dst_x(bb, 32) || !gfx_bitblt_check_src_x(bb, 16)) { + return false; + } + dma2d_wait(); if (!dma2d_accessible(bb->dst_row) || !dma2d_accessible(bb->src_row)) { @@ -670,6 +705,11 @@ bool dma2d_rgba8888_blend_mono4(const gfx_bitblt_t* params) { return false; } + if (!gfx_bitblt_check_dst_x(params, 32) || + !gfx_bitblt_check_src_x(params, 4)) { + return false; + } + dma2d_wait(); gfx_bitblt_t bb_copy = *params; @@ -736,6 +776,10 @@ bool dma2d_rgba8888_blend_mono8(const gfx_bitblt_t* bb) { return false; } + if (!gfx_bitblt_check_dst_x(bb, 32) || !gfx_bitblt_check_src_x(bb, 8)) { + return false; + } + dma2d_wait(); if (!dma2d_accessible(bb->dst_row) || !dma2d_accessible(bb->src_row)) { @@ -775,6 +819,10 @@ bool dma2d_rgba8888_copy_mono8(const gfx_bitblt_t* bb) { return false; } + if (!gfx_bitblt_check_dst_x(bb, 32) || !gfx_bitblt_check_src_x(bb, 8)) { + return false; + } + dma2d_wait(); if (!dma2d_accessible(bb->dst_row) || !dma2d_accessible(bb->src_row)) { @@ -806,6 +854,10 @@ bool dma2d_rgba8888_copy_rgba8888(const gfx_bitblt_t* bb) { return false; } + if (!gfx_bitblt_check_dst_x(bb, 32) || !gfx_bitblt_check_src_x(bb, 32)) { + return false; + } + dma2d_wait(); if (!dma2d_accessible(bb->dst_row) || !dma2d_accessible(bb->src_row)) { @@ -843,6 +895,10 @@ static bool dma2d_rgba8888_copy_ycbcr(const gfx_bitblt_t* bb, uint32_t css) { return false; } + if (!gfx_bitblt_check_dst_x(bb, 32)) { + return false; + } + dma2d_wait(); if (!dma2d_accessible(bb->dst_row) || !dma2d_accessible(bb->src_row)) { diff --git a/core/embed/gfx/inc/gfx/gfx_bitblt.h b/core/embed/gfx/inc/gfx/gfx_bitblt.h index 7f6a4af8b2..f1cc17b061 100644 --- a/core/embed/gfx/inc/gfx/gfx_bitblt.h +++ b/core/embed/gfx/inc/gfx/gfx_bitblt.h @@ -87,6 +87,27 @@ void gfx_bitblt_deinit(void); #endif // KERNEL_MODE +// Checks if src_x and width are within the bounds of the source bitmap +static inline bool gfx_bitblt_check_src_x(const gfx_bitblt_t* bb, + size_t pixel_bits) { + return (bb->src_x + bb->width >= bb->src_x) && // overflow check + (((bb->src_x + bb->width) * pixel_bits + 7) / 8 <= bb->src_stride); +} + +// Checks if dst_x and width are within the bounds of the destination bitmap +static inline bool gfx_bitblt_check_dst_x(const gfx_bitblt_t* bb, + size_t pixel_bits) { + return (bb->dst_x + bb->width >= bb->dst_x) && // overflow check + (((bb->dst_x + bb->width) * pixel_bits + 7) / 8 <= bb->dst_stride); +} + +// Checks if dst_y and height are within the bounds of the destination bitmap +static inline bool gfx_bitblt_check_dst_y(const gfx_bitblt_t* bb, + size_t fb_size) { + return (bb->dst_y + bb->height >= bb->dst_y) && // overflow check + (bb->dst_y + bb->height) * bb->dst_stride <= fb_size; +} + // If the bitblt operation is asynchronous, waits until it's finished void gfx_bitblt_wait(void); diff --git a/core/embed/io/display/ltdc_dsi/display_fb_rgb565.c b/core/embed/io/display/ltdc_dsi/display_fb_rgb565.c index da63656841..f0dc3913de 100644 --- a/core/embed/io/display/ltdc_dsi/display_fb_rgb565.c +++ b/core/embed/io/display/ltdc_dsi/display_fb_rgb565.c @@ -16,6 +16,12 @@ void display_copy_rgb565(const gfx_bitblt_t *bb) { bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; + if (!gfx_bitblt_check_dst_x(&bb_new, 16) || + !gfx_bitblt_check_src_x(&bb_new, 16) || + !gfx_bitblt_check_dst_y(&bb_new, fb.size)) { + return; + } + gfx_rgb565_copy_rgb565(&bb_new); } @@ -30,6 +36,11 @@ void display_fill(const gfx_bitblt_t *bb) { bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; + if (!gfx_bitblt_check_dst_x(&bb_new, 16) || + !gfx_bitblt_check_dst_y(&bb_new, fb.size)) { + return; + } + gfx_rgb565_fill(&bb_new); } @@ -44,6 +55,12 @@ void display_copy_mono1p(const gfx_bitblt_t *bb) { bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; + if (!gfx_bitblt_check_dst_x(&bb_new, 16) || + !gfx_bitblt_check_src_x(&bb_new, 1) || + !gfx_bitblt_check_dst_y(&bb_new, fb.size)) { + return; + } + gfx_rgb565_copy_mono1p(&bb_new); } diff --git a/core/embed/io/display/ltdc_dsi/display_fb_rgb888.c b/core/embed/io/display/ltdc_dsi/display_fb_rgb888.c index 0392b7c6f5..3b9620f62d 100644 --- a/core/embed/io/display/ltdc_dsi/display_fb_rgb888.c +++ b/core/embed/io/display/ltdc_dsi/display_fb_rgb888.c @@ -18,6 +18,11 @@ void display_fill(const gfx_bitblt_t *bb) { bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; + if (!gfx_bitblt_check_dst_x(&bb_new, 32) || + !gfx_bitblt_check_dst_y(&bb_new, fb.size)) { + return; + } + gfx_rgba8888_fill(&bb_new); } @@ -32,6 +37,12 @@ void display_copy_rgb565(const gfx_bitblt_t *bb) { bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; + if (!gfx_bitblt_check_dst_x(&bb_new, 32) || + !gfx_bitblt_check_src_x(&bb_new, 16) || + !gfx_bitblt_check_dst_y(&bb_new, fb.size)) { + return; + } + gfx_rgba8888_copy_rgb565(&bb_new); } @@ -46,6 +57,12 @@ void display_copy_mono1p(const gfx_bitblt_t *bb) { bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; + if (!gfx_bitblt_check_dst_x(&bb_new, 32) || + !gfx_bitblt_check_src_x(&bb_new, 1) || + !gfx_bitblt_check_dst_y(&bb_new, fb.size)) { + return; + } + gfx_rgba8888_copy_mono1p(&bb_new); } diff --git a/core/embed/io/display/st-7789/display_fb.c b/core/embed/io/display/st-7789/display_fb.c index b3fda4bbfa..2565aaa9a3 100644 --- a/core/embed/io/display/st-7789/display_fb.c +++ b/core/embed/io/display/st-7789/display_fb.c @@ -279,6 +279,11 @@ void display_fill(const gfx_bitblt_t *bb) { bb_new.dst_row = (uint16_t *)((uintptr_t)fb.ptr + fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; + if (!gfx_bitblt_check_dst_x(&bb_new, 16) || + !gfx_bitblt_check_dst_y(&bb_new, fb.size)) { + return; + } + gfx_rgb565_fill(&bb_new); } @@ -293,6 +298,12 @@ void display_copy_rgb565(const gfx_bitblt_t *bb) { bb_new.dst_row = (uint16_t *)((uintptr_t)fb.ptr + fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; + if (!gfx_bitblt_check_dst_x(&bb_new, 16) || + !gfx_bitblt_check_src_x(&bb_new, 16) || + !gfx_bitblt_check_dst_y(&bb_new, fb.size)) { + return; + } + gfx_rgb565_copy_rgb565(&bb_new); } @@ -307,6 +318,12 @@ void display_copy_mono1p(const gfx_bitblt_t *bb) { bb_new.dst_row = (uint16_t *)((uintptr_t)fb.ptr + fb.stride * bb_new.dst_y); bb_new.dst_stride = fb.stride; + if (!gfx_bitblt_check_dst_x(&bb_new, 16) || + !gfx_bitblt_check_src_x(&bb_new, 1) || + !gfx_bitblt_check_dst_y(&bb_new, fb.size)) { + return; + } + gfx_rgb565_copy_mono1p(&bb_new); } diff --git a/core/embed/io/display/st-7789/display_nofb.c b/core/embed/io/display/st-7789/display_nofb.c index 95b1712c2c..4ca6fddd19 100644 --- a/core/embed/io/display/st-7789/display_nofb.c +++ b/core/embed/io/display/st-7789/display_nofb.c @@ -79,6 +79,27 @@ static inline void set_window(const gfx_bitblt_t* bb) { bb->dst_y + bb->height + 1); } +// Checks if the destination rectangle is withing the display bounds +static inline bool gfx_bitblt_check_dst_xy(const gfx_bitblt_t* bb) { + if (bb->dst_x + bb->width < bb->dst_x) { // overflow check + return false; + } + + if (bb->dst_x + bb->width > DISPLAY_RESX) { + return false; + } + + if (bb->dst_y + bb->height < bb->dst_y) { // overflow check + return false; + } + + if (bb->dst_y + bb->height > DISPLAY_RESY) { + return false; + } + + return true; +} + // For future notice, if we ever want to do a new model using progressive // rendering. // @@ -88,6 +109,10 @@ static inline void set_window(const gfx_bitblt_t* bb) { // to one with DMA2D while copying the other to the display with DMA. void display_fill(const gfx_bitblt_t* bb) { + if (!gfx_bitblt_check_dst_xy(bb)) { + return; + } + set_window(bb); uint16_t height = bb->height; @@ -100,6 +125,10 @@ void display_fill(const gfx_bitblt_t* bb) { } void display_copy_rgb565(const gfx_bitblt_t* bb) { + if (!gfx_bitblt_check_dst_xy(bb) || !gfx_bitblt_check_src_x(bb, 16)) { + return; + } + set_window(bb); uint16_t* src_ptr = (uint16_t*)bb->src_row + bb->src_x; @@ -114,6 +143,10 @@ void display_copy_rgb565(const gfx_bitblt_t* bb) { } void display_copy_mono1p(const gfx_bitblt_t* bb) { + if (!gfx_bitblt_check_dst_xy(bb) || !gfx_bitblt_check_src_x(bb, 1)) { + return; + } + set_window(bb); uint8_t* src = (uint8_t*)bb->src_row; diff --git a/core/embed/io/display/stm32f429i-disc1/display_driver.c b/core/embed/io/display/stm32f429i-disc1/display_driver.c index 77452a42d7..d4ac62a33c 100644 --- a/core/embed/io/display/stm32f429i-disc1/display_driver.c +++ b/core/embed/io/display/stm32f429i-disc1/display_driver.c @@ -165,6 +165,11 @@ void display_fill(const gfx_bitblt_t *bb) { bb_new.dst_row = drv->framebuf + (DISPLAY_RESX * bb_new.dst_y); bb_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t); + if (!gfx_bitblt_check_dst_x(&bb_new, 16) || + !gfx_bitblt_check_dst_y(&bb_new, FRAME_BUFFER_SIZE)) { + return; + } + gfx_rgb565_fill(&bb_new); } @@ -179,6 +184,12 @@ void display_copy_rgb565(const gfx_bitblt_t *bb) { bb_new.dst_row = drv->framebuf + (DISPLAY_RESX * bb_new.dst_y); bb_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t); + if (!gfx_bitblt_check_dst_x(&bb_new, 16) || + !gfx_bitblt_check_src_x(&bb_new, 16) || + !gfx_bitblt_check_dst_y(&bb_new, FRAME_BUFFER_SIZE)) { + return; + } + gfx_rgb565_copy_rgb565(&bb_new); } @@ -193,6 +204,12 @@ void display_copy_mono1p(const gfx_bitblt_t *bb) { bb_new.dst_row = drv->framebuf + (DISPLAY_RESX * bb_new.dst_y); bb_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t); + if (!gfx_bitblt_check_dst_x(&bb_new, 16) || + !gfx_bitblt_check_src_x(&bb_new, 1) || + !gfx_bitblt_check_dst_y(&bb_new, FRAME_BUFFER_SIZE)) { + return; + } + gfx_rgb565_copy_mono1p(&bb_new); } diff --git a/core/embed/io/display/vg-2864/display_driver.c b/core/embed/io/display/vg-2864/display_driver.c index b39dfd42f6..4f9992fb8f 100644 --- a/core/embed/io/display/vg-2864/display_driver.c +++ b/core/embed/io/display/vg-2864/display_driver.c @@ -436,6 +436,11 @@ void display_fill(const gfx_bitblt_t *bb) { bb_new.dst_row = &(((uint8_t *)fb.ptr)[DISPLAY_RESX * bb_new.dst_y]); bb_new.dst_stride = DISPLAY_RESX; + if (!gfx_bitblt_check_dst_x(&bb_new, 8) || + !gfx_bitblt_check_dst_y(&bb_new, fb.size)) { + return; + } + gfx_mono8_fill(&bb_new); } @@ -450,6 +455,12 @@ void display_copy_mono1p(const gfx_bitblt_t *bb) { bb_new.dst_row = &(((uint8_t *)fb.ptr)[DISPLAY_RESX * bb_new.dst_y]); bb_new.dst_stride = DISPLAY_RESX; + if (!gfx_bitblt_check_dst_x(&bb_new, 8) || + !gfx_bitblt_check_src_x(&bb_new, 1) || + !gfx_bitblt_check_dst_y(&bb_new, fb.size)) { + return; + } + gfx_mono8_copy_mono1p(&bb_new); } diff --git a/core/embed/sys/mpu/stm32u5/mpu.c b/core/embed/sys/mpu/stm32u5/mpu.c index 7cc98e293a..ed4ae8f693 100644 --- a/core/embed/sys/mpu/stm32u5/mpu.c +++ b/core/embed/sys/mpu/stm32u5/mpu.c @@ -306,6 +306,7 @@ bool mpu_inside_active_fb(const void* addr, size_t size) { irq_key_t lock = irq_lock(); bool result = + ((uintptr_t)addr + size >= (uintptr_t)addr) && // overflow check ((uintptr_t)addr >= drv->active_fb_addr) && ((uintptr_t)addr + size <= drv->active_fb_addr + drv->active_fb_size);