From cbaaf8fe42dce5ec39d77db3334b672dc745fa9c Mon Sep 17 00:00:00 2001 From: Courtney Goeltzenleuchter Date: Tue, 8 Apr 2014 09:10:09 -0600 Subject: [PATCH] mesa: add bounds checking to eliminate buffer overrun Decompressing ETC2 textures was causing intermitent segfault by copying resulting 4x4 texel block to the destination texture regardless of the size of the destination texture. Issue found via application crash in GLBenchmark 3.0's Manhattan test. v2: add more detail comment. Compute limit outside inner loops. v3: add bugzilla reference v4: Correct cc syntax in commit log v5: really grab the right patch Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=74988 Cc: "9.2 10.0 10.1" Reviewed-by: Kenneth Graunke Reviewed-by: Ian Romanick [v1, suggested v2-3] (cherry picked from commit cb4ad1368551b64756c7b6e2007588e34739b188) --- src/mesa/main/texcompress_etc.c | 78 +++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/src/mesa/main/texcompress_etc.c b/src/mesa/main/texcompress_etc.c index a06d29f19aa..080b79024a8 100644 --- a/src/mesa/main/texcompress_etc.c +++ b/src/mesa/main/texcompress_etc.c @@ -679,14 +679,25 @@ etc2_unpack_rgb8(uint8_t *dst_row, for (y = 0; y < height; y += bh) { const uint8_t *src = src_row; + /* + * Destination texture may not be a multiple of four texels in + * height. Compute a safe height to avoid writing outside the texture. + */ + const unsigned h = MIN2(bh, height - y); for (x = 0; x < width; x+= bw) { etc2_rgb8_parse_block(&block, src, false /* punchthrough_alpha */); - for (j = 0; j < bh; j++) { + /* + * Destination texture may not be a multiple of four texels in + * width. Compute a safe width to avoid writing outside the texture. + */ + const unsigned w = MIN2(bw, width - x); + + for (j = 0; j < h; j++) { uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps; - for (i = 0; i < bw; i++) { + for (i = 0; i < w; i++) { etc2_rgb8_fetch_texel(&block, i, j, dst, false /* punchthrough_alpha */); dst[3] = 255; @@ -716,14 +727,17 @@ etc2_unpack_srgb8(uint8_t *dst_row, for (y = 0; y < height; y += bh) { const uint8_t *src = src_row; + const unsigned h = MIN2(bh, height - y); for (x = 0; x < width; x+= bw) { + const unsigned w = MIN2(bw, width - x); etc2_rgb8_parse_block(&block, src, false /* punchthrough_alpha */); - for (j = 0; j < bh; j++) { + + for (j = 0; j < h; j++) { uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps; - for (i = 0; i < bw; i++) { + for (i = 0; i < w; i++) { etc2_rgb8_fetch_texel(&block, i, j, dst, false /* punchthrough_alpha */); /* Convert to MESA_FORMAT_SARGB8 */ @@ -760,13 +774,15 @@ etc2_unpack_rgba8(uint8_t *dst_row, for (y = 0; y < height; y += bh) { const uint8_t *src = src_row; + const unsigned h = MIN2(bh, height - y); for (x = 0; x < width; x+= bw) { + const unsigned w = MIN2(bw, width - x); etc2_rgba8_parse_block(&block, src); - for (j = 0; j < bh; j++) { + for (j = 0; j < h; j++) { uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps; - for (i = 0; i < bw; i++) { + for (i = 0; i < w; i++) { etc2_rgba8_fetch_texel(&block, i, j, dst); dst += comps; } @@ -796,14 +812,16 @@ etc2_unpack_srgb8_alpha8(uint8_t *dst_row, uint8_t tmp; for (y = 0; y < height; y += bh) { + const unsigned h = MIN2(bh, height - y); const uint8_t *src = src_row; for (x = 0; x < width; x+= bw) { + const unsigned w = MIN2(bw, width - x); etc2_rgba8_parse_block(&block, src); - for (j = 0; j < bh; j++) { + for (j = 0; j < h; j++) { uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps; - for (i = 0; i < bw; i++) { + for (i = 0; i < w; i++) { etc2_rgba8_fetch_texel(&block, i, j, dst); /* Convert to MESA_FORMAT_SARGB8 */ @@ -838,14 +856,16 @@ etc2_unpack_r11(uint8_t *dst_row, unsigned x, y, i, j; for (y = 0; y < height; y += bh) { + const unsigned h = MIN2(bh, height - y); const uint8_t *src = src_row; for (x = 0; x < width; x+= bw) { + const unsigned w = MIN2(bw, width - x); etc2_r11_parse_block(&block, src); - for (j = 0; j < bh; j++) { + for (j = 0; j < h; j++) { uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps * comp_size; - for (i = 0; i < bw; i++) { + for (i = 0; i < w; i++) { etc2_r11_fetch_texel(&block, i, j, dst); dst += comps * comp_size; } @@ -873,16 +893,18 @@ etc2_unpack_rg11(uint8_t *dst_row, unsigned x, y, i, j; for (y = 0; y < height; y += bh) { + const unsigned h = MIN2(bh, height - y); const uint8_t *src = src_row; for (x = 0; x < width; x+= bw) { + const unsigned w = MIN2(bw, width - x); /* red component */ etc2_r11_parse_block(&block, src); - for (j = 0; j < bh; j++) { + for (j = 0; j < h; j++) { uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps * comp_size; - for (i = 0; i < bw; i++) { + for (i = 0; i < w; i++) { etc2_r11_fetch_texel(&block, i, j, dst); dst += comps * comp_size; } @@ -890,10 +912,10 @@ etc2_unpack_rg11(uint8_t *dst_row, /* green component */ etc2_r11_parse_block(&block, src + 8); - for (j = 0; j < bh; j++) { + for (j = 0; j < h; j++) { uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps * comp_size; - for (i = 0; i < bw; i++) { + for (i = 0; i < w; i++) { etc2_r11_fetch_texel(&block, i, j, dst + comp_size); dst += comps * comp_size; } @@ -921,15 +943,17 @@ etc2_unpack_signed_r11(uint8_t *dst_row, unsigned x, y, i, j; for (y = 0; y < height; y += bh) { + const unsigned h = MIN2(bh, height - y); const uint8_t *src = src_row; for (x = 0; x < width; x+= bw) { + const unsigned w = MIN2(bw, width - x); etc2_r11_parse_block(&block, src); - for (j = 0; j < bh; j++) { + for (j = 0; j < h; j++) { uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps * comp_size; - for (i = 0; i < bw; i++) { + for (i = 0; i < w; i++) { etc2_signed_r11_fetch_texel(&block, i, j, dst); dst += comps * comp_size; } @@ -957,16 +981,18 @@ etc2_unpack_signed_rg11(uint8_t *dst_row, unsigned x, y, i, j; for (y = 0; y < height; y += bh) { + const unsigned h = MIN2(bh, height - y); const uint8_t *src = src_row; for (x = 0; x < width; x+= bw) { + const unsigned w = MIN2(bw, width - x); /* red component */ etc2_r11_parse_block(&block, src); - for (j = 0; j < bh; j++) { + for (j = 0; j < h; j++) { uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps * comp_size; - for (i = 0; i < bw; i++) { + for (i = 0; i < w; i++) { etc2_signed_r11_fetch_texel(&block, i, j, dst); dst += comps * comp_size; } @@ -974,10 +1000,10 @@ etc2_unpack_signed_rg11(uint8_t *dst_row, /* green component */ etc2_r11_parse_block(&block, src + 8); - for (j = 0; j < bh; j++) { + for (j = 0; j < h; j++) { uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps * comp_size; - for (i = 0; i < bw; i++) { + for (i = 0; i < w; i++) { etc2_signed_r11_fetch_texel(&block, i, j, dst + comp_size); dst += comps * comp_size; } @@ -1002,14 +1028,16 @@ etc2_unpack_rgb8_punchthrough_alpha1(uint8_t *dst_row, unsigned x, y, i, j; for (y = 0; y < height; y += bh) { + const unsigned h = MIN2(bh, height - y); const uint8_t *src = src_row; for (x = 0; x < width; x+= bw) { + const unsigned w = MIN2(bw, width - x); etc2_rgb8_parse_block(&block, src, true /* punchthrough_alpha */); - for (j = 0; j < bh; j++) { + for (j = 0; j < h; j++) { uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps; - for (i = 0; i < bw; i++) { + for (i = 0; i < w; i++) { etc2_rgb8_fetch_texel(&block, i, j, dst, true /* punchthrough_alpha */); dst += comps; @@ -1037,14 +1065,16 @@ etc2_unpack_srgb8_punchthrough_alpha1(uint8_t *dst_row, uint8_t tmp; for (y = 0; y < height; y += bh) { + const unsigned h = MIN2(bh, height - y); const uint8_t *src = src_row; for (x = 0; x < width; x+= bw) { + const unsigned w = MIN2(bw, width - x); etc2_rgb8_parse_block(&block, src, true /* punchthrough_alpha */); - for (j = 0; j < bh; j++) { + for (j = 0; j < h; j++) { uint8_t *dst = dst_row + (y + j) * dst_stride + x * comps; - for (i = 0; i < bw; i++) { + for (i = 0; i < w; i++) { etc2_rgb8_fetch_texel(&block, i, j, dst, true /* punchthrough_alpha */); /* Convert to MESA_FORMAT_SARGB8 */