From 464e6ca987c3c149f7918a0c9f920b150a2dd3b5 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Wed, 8 Apr 2015 17:21:42 +0900 Subject: [PATCH] Evas masking: Avoid potential crashes (SW) Make sure not to sample the mask image outside its boundaries. This is a series of last resort checks. I can not reproduce the crashes but know they have happened. I used EINA_UNLIKELY more for clarity than for compiler optimizations. --- src/lib/evas/common/evas_font_compress.c | 10 +++++ src/lib/evas/common/evas_rectangle_main.c | 26 +++++++++++- src/lib/evas/common/evas_scale_sample.c | 55 ++++++++++++++++++++------ src/lib/evas/common/evas_scale_smooth_scaler.c | 13 ++++++ 4 files changed, 89 insertions(+), 15 deletions(-) diff --git a/src/lib/evas/common/evas_font_compress.c b/src/lib/evas/common/evas_font_compress.c index 6c84aa4..1e13e53 100644 --- a/src/lib/evas/common/evas_font_compress.c +++ b/src/lib/evas/common/evas_font_compress.c @@ -534,6 +534,16 @@ evas_common_font_glyph_draw(RGBA_Font_Glyph *fg, buf = alloca(sizeof(DATA32) * w * h); + // Adjust clipping info + if (EINA_UNLIKELY((x + x1) < dc->clip.mask_x)) + x1 = dc->clip.mask_x - x; + if (EINA_UNLIKELY((y + y1) < dc->clip.mask_y)) + y1 = dc->clip.mask_y - y; + if (EINA_UNLIKELY((x + x2) > (int)(x + x1 + im->cache_entry.w))) + x2 = x1 + im->cache_entry.w; + if (EINA_UNLIKELY((y + y2) > (int)(y + y1 + im->cache_entry.h))) + y2 = y1 + im->cache_entry.h; + // Step 1: alpha glyph drawing src8 = evas_common_font_glyph_uncompress(fg, NULL, NULL); if (!src8) return; diff --git a/src/lib/evas/common/evas_rectangle_main.c b/src/lib/evas/common/evas_rectangle_main.c index d952f41..220fd0f 100644 --- a/src/lib/evas/common/evas_rectangle_main.c +++ b/src/lib/evas/common/evas_rectangle_main.c @@ -135,7 +135,18 @@ rectangle_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, in #endif { if (mask_ie) - func = evas_common_gfx_func_composite_mask_color_span_get(dc->col.col, dst->cache_entry.flags.alpha, w, dc->render_op); + { + func = evas_common_gfx_func_composite_mask_color_span_get(dc->col.col, dst->cache_entry.flags.alpha, w, dc->render_op); + // Adjust clipping info + if (EINA_UNLIKELY((x - dc->clip.mask_x) < 0)) + x = dc->clip.mask_x; + if (EINA_UNLIKELY((y - dc->clip.mask_y) < 0)) + y = dc->clip.mask_y; + if (EINA_UNLIKELY((x - dc->clip.mask_x + w) > (int)mask_ie->cache_entry.w)) + w = mask_ie->cache_entry.w + dc->clip.mask_x - x; + if (EINA_UNLIKELY((y - dc->clip.mask_y + h) > (int)mask_ie->cache_entry.h)) + h = mask_ie->cache_entry.h + dc->clip.mask_y - y; + } else func = evas_common_gfx_func_composite_color_span_get(dc->col.col, dst->cache_entry.flags.alpha, w, dc->render_op); ptr = dst->image.data + (y * dst->cache_entry.w) + x; @@ -165,7 +176,18 @@ evas_common_rectangle_rgba_draw(RGBA_Image *dst, DATA32 color, int render_op, in int yy; if (mask_ie) - func = evas_common_gfx_func_composite_mask_color_span_get(color, dst->cache_entry.flags.alpha, w, render_op); + { + func = evas_common_gfx_func_composite_mask_color_span_get(color, dst->cache_entry.flags.alpha, w, render_op); + // Adjust clipping info + if (EINA_UNLIKELY((x - mask_x) < 0)) + x = mask_x; + if (EINA_UNLIKELY((y - mask_y) < 0)) + y = mask_y; + if (EINA_UNLIKELY((x - mask_x + w) > (int)mask_ie->cache_entry.w)) + w = mask_ie->cache_entry.w + mask_x - x; + if (EINA_UNLIKELY((y - mask_y + h) > (int)mask_ie->cache_entry.h)) + h = mask_ie->cache_entry.h + mask_y - y; + } else func = evas_common_gfx_func_composite_color_span_get(color, dst->cache_entry.flags.alpha, w, render_op); diff --git a/src/lib/evas/common/evas_scale_sample.c b/src/lib/evas/common/evas_scale_sample.c index 40dd7f8..2de5632 100644 --- a/src/lib/evas/common/evas_scale_sample.c +++ b/src/lib/evas/common/evas_scale_sample.c @@ -131,7 +131,7 @@ _evas_common_scale_rgba_sample_scale_mask(int y, int dst_clip_x, int dst_clip_y, int dst_clip_w, int dst_clip_h, int dst_w, int mask_x, int mask_y, - DATA32 **row_ptr, int *lin_ptr, RGBA_Image *im, + DATA32 **row_ptr, int *lin_ptr, RGBA_Image *mask_ie, DATA32 *dptr, RGBA_Gfx_Func func, RGBA_Gfx_Func func2, unsigned int mul_col) { @@ -141,14 +141,24 @@ _evas_common_scale_rgba_sample_scale_mask(int y, /* a scanline buffer */ buf = alloca(dst_clip_w * sizeof(DATA32)); + // Adjust clipping info + if (EINA_UNLIKELY((dst_clip_x - mask_x) < 0)) + dst_clip_x = mask_x; + if (EINA_UNLIKELY((dst_clip_y - mask_y + y) < 0)) + dst_clip_y = mask_y + y; + if (EINA_UNLIKELY((dst_clip_x - mask_x + dst_clip_w) > (int)mask_ie->cache_entry.w)) + dst_clip_w = mask_x - mask_ie->cache_entry.w - dst_clip_x; + if (EINA_UNLIKELY((dst_clip_y - mask_y + y + dst_clip_h) > (int)mask_ie->cache_entry.h)) + dst_clip_h = mask_y + y - mask_ie->cache_entry.h - dst_clip_y; + dptr = dptr + dst_w * y; for (; y < dst_clip_h; y++) { DATA8 *mask; dst_ptr = buf; - mask = im->image.data8 - + ((dst_clip_y - mask_y + y) * im->cache_entry.w) + mask = mask_ie->image.data8 + + ((dst_clip_y - mask_y + y) * mask_ie->cache_entry.w) + (dst_clip_x - mask_x); for (x = 0; x < dst_clip_w; x++) @@ -325,6 +335,15 @@ evas_common_scale_rgba_sample_draw(RGBA_Image *src, RGBA_Image *dst, int dst_cli } else func = evas_common_gfx_func_composite_pixel_mask_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, render_op); + // Adjust clipping info + if (EINA_UNLIKELY((dst_clip_x - mask_x) < 0)) + dst_clip_x = mask_x; + if (EINA_UNLIKELY((dst_clip_y - mask_y) < 0)) + dst_clip_y = mask_y; + if (EINA_UNLIKELY((dst_clip_x - mask_x + dst_clip_w) > (int)mask_ie->cache_entry.w)) + dst_clip_w = mask_ie->cache_entry.w - dst_clip_x + mask_x; + if (EINA_UNLIKELY((dst_clip_y - mask_y + dst_clip_h) > (int)mask_ie->cache_entry.h)) + dst_clip_h = mask_ie->cache_entry.h - dst_clip_y + mask_y; } if ((dst_region_w == src_region_w) && (dst_region_h == src_region_h)) @@ -449,8 +468,9 @@ scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst, DATA32 *ptr, *dst_ptr, *src_data, *dst_data; DATA8 *mask; int dst_clip_x, dst_clip_y, dst_clip_w, dst_clip_h; - int src_w, src_h, dst_w, dst_h; + int src_w, src_h, dst_w, dst_h, mask_x, mask_y; RGBA_Gfx_Func func, func2 = NULL; + RGBA_Image *mask_ie = dc->clip.mask; if (!(RECTS_INTERSECT(dst_region_x, dst_region_y, dst_region_w, dst_region_h, 0, 0, dst->cache_entry.w, dst->cache_entry.h))) return EINA_FALSE; @@ -578,7 +598,7 @@ scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst, /* figure out dest start ptr */ dst_ptr = dst_data + dst_clip_x + (dst_clip_y * dst_w); - if (!dc->clip.mask) + if (!mask_ie) { if (dc->mul.use) func = evas_common_gfx_func_composite_pixel_color_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dc->mul.col, dst->cache_entry.flags.alpha, dst_clip_w, dc->render_op); @@ -590,6 +610,17 @@ scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst, func = evas_common_gfx_func_composite_pixel_mask_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, dc->render_op); if (dc->mul.use) func2 = evas_common_gfx_func_composite_pixel_color_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dc->mul.col, dst->cache_entry.flags.alpha, dst_clip_w, EVAS_RENDER_COPY); + // Adjust clipping info + mask_x = dc->clip.mask_x; + mask_y = dc->clip.mask_y; + if (EINA_UNLIKELY((dst_clip_x - mask_x) < 0)) + dst_clip_x = mask_x; + if (EINA_UNLIKELY((dst_clip_y - mask_y) < 0)) + dst_clip_y = mask_y; + if (EINA_UNLIKELY((dst_clip_x - mask_x + dst_clip_w) > (int)mask_ie->cache_entry.w)) + dst_clip_w = mask_ie->cache_entry.w - dst_clip_x + mask_x; + if (EINA_UNLIKELY((dst_clip_y - mask_y + dst_clip_h) > (int)mask_ie->cache_entry.h)) + dst_clip_h = mask_ie->cache_entry.h - dst_clip_y + mask_y; } if ((dst_region_w == src_region_w) && (dst_region_h == src_region_h)) @@ -621,18 +652,16 @@ scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst, ptr = src_data + ((dst_clip_y - dst_region_y + src_region_y) * src_w) + (dst_clip_x - dst_region_x) + src_region_x; /* image masking */ - if (dc->clip.mask) + if (mask_ie) { - RGBA_Image *im = dc->clip.mask; - if (dc->mul.use) buf = alloca(dst_clip_w * sizeof(DATA32)); for (y = 0; y < dst_clip_h; y++) { - mask = im->image.data8 - + ((dst_clip_y - dc->clip.mask_y + y) * im->cache_entry.w) - + (dst_clip_x - dc->clip.mask_x); + mask = mask_ie->image.data8 + + ((dst_clip_y - mask_y + y) * mask_ie->cache_entry.w) + + (dst_clip_x - mask_x); /* * blend here [clip_w *] ptr -> dst_ptr * */ if (dc->mul.use) @@ -723,8 +752,8 @@ scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst, local.dst_clip_h = dst_clip_h; local.dst_clip_w = dst_clip_w; local.dst_w = dst_w; - local.mask_x = dc->clip.mask_x; - local.mask_y = dc->clip.mask_y; + local.mask_x = mask_x; + local.mask_y = mask_y; local.mul_col = mul_col; msg = eina_thread_queue_send(thread_queue, sizeof (Evas_Scale_Msg), &ref); diff --git a/src/lib/evas/common/evas_scale_smooth_scaler.c b/src/lib/evas/common/evas_scale_smooth_scaler.c index 0eea162..24bc28e 100644 --- a/src/lib/evas/common/evas_scale_smooth_scaler.c +++ b/src/lib/evas/common/evas_scale_smooth_scaler.c @@ -131,6 +131,19 @@ SCALE_FUNC(RGBA_Image *src, RGBA_Image *dst, int dst_clip_x, int dst_clip_y, int /* figure out dest start ptr */ dst_ptr = dst->image.data + dst_clip_x + (dst_clip_y * dst_w); + if (mask_ie) + { + // Adjust clipping info + if (EINA_UNLIKELY((dst_clip_x - mask_x) < 0)) + dst_clip_x = mask_x; + if (EINA_UNLIKELY((dst_clip_y - mask_y) < 0)) + dst_clip_y = mask_y; + if (EINA_UNLIKELY((dst_clip_x - mask_x + dst_clip_w) > (int)mask_ie->cache_entry.w)) + dst_clip_w = mask_ie->cache_entry.w - dst_clip_x + mask_x; + if (EINA_UNLIKELY((dst_clip_y - mask_y + dst_clip_h) > (int)mask_ie->cache_entry.h)) + dst_clip_h = mask_ie->cache_entry.h - dst_clip_y + mask_y; + } + /* FIXME: * * things to do later for speedups: -- 2.7.4