| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "Fuzz.h" | 8 #include "Fuzz.h" |
| 9 #include "SkCanvas.h" | 9 #include "SkCanvas.h" |
| 10 #include "SkCodec.h" | 10 #include "SkCodec.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 | 27 |
| 28 DEFINE_string2(type, t, "api", "How to interpret --bytes, either 'image_scale',
'image_mode', 'skp', 'icc', or 'api'."); | 28 DEFINE_string2(type, t, "api", "How to interpret --bytes, either 'image_scale',
'image_mode', 'skp', 'icc', or 'api'."); |
| 29 DEFINE_string2(dump, d, "", "If not empty, dump 'image*' or 'skp' types as a PNG
with this name."); | 29 DEFINE_string2(dump, d, "", "If not empty, dump 'image*' or 'skp' types as a PNG
with this name."); |
| 30 | 30 |
| 31 static int printUsage(const char* name) { | 31 static int printUsage(const char* name) { |
| 32 SkDebugf("Usage: %s -t <type> -b <path/to/file> [-n api-to-fuzz]\n", name); | 32 SkDebugf("Usage: %s -t <type> -b <path/to/file> [-n api-to-fuzz]\n", name); |
| 33 return 1; | 33 return 1; |
| 34 } | 34 } |
| 35 static uint8_t calculate_option(SkData*); | 35 static uint8_t calculate_option(SkData*); |
| 36 | 36 |
| 37 static int fuzz_api(SkData*); | 37 static int fuzz_api(sk_sp<SkData>); |
| 38 static int fuzz_img(SkData*, uint8_t, uint8_t); | 38 static int fuzz_img(sk_sp<SkData>, uint8_t, uint8_t); |
| 39 static int fuzz_skp(SkData*); | 39 static int fuzz_skp(sk_sp<SkData>); |
| 40 static int fuzz_icc(SkData*); | 40 static int fuzz_icc(sk_sp<SkData>); |
| 41 static int fuzz_color_deserialize(SkData*); | 41 static int fuzz_color_deserialize(sk_sp<SkData>); |
| 42 | 42 |
| 43 int main(int argc, char** argv) { | 43 int main(int argc, char** argv) { |
| 44 SkCommandLineFlags::Parse(argc, argv); | 44 SkCommandLineFlags::Parse(argc, argv); |
| 45 | 45 |
| 46 const char* path = FLAGS_bytes.isEmpty() ? argv[0] : FLAGS_bytes[0]; | 46 const char* path = FLAGS_bytes.isEmpty() ? argv[0] : FLAGS_bytes[0]; |
| 47 sk_sp<SkData> bytes(SkData::MakeFromFileName(path)); | 47 sk_sp<SkData> bytes(SkData::MakeFromFileName(path)); |
| 48 if (!bytes) { | 48 if (!bytes) { |
| 49 SkDebugf("Could not read %s\n", path); | 49 SkDebugf("Could not read %s\n", path); |
| 50 return 2; | 50 return 2; |
| 51 } | 51 } |
| 52 | 52 |
| 53 uint8_t option = calculate_option(bytes.get()); | 53 uint8_t option = calculate_option(bytes.get()); |
| 54 | 54 |
| 55 if (!FLAGS_type.isEmpty()) { | 55 if (!FLAGS_type.isEmpty()) { |
| 56 switch (FLAGS_type[0][0]) { | 56 switch (FLAGS_type[0][0]) { |
| 57 case 'a': return fuzz_api(bytes.get()); | 57 case 'a': return fuzz_api(bytes); |
| 58 | 58 |
| 59 case 'c': return fuzz_color_deserialize(bytes.get()); | 59 case 'c': return fuzz_color_deserialize(bytes); |
| 60 | 60 |
| 61 case 'i': | 61 case 'i': |
| 62 if (FLAGS_type[0][1] == 'c') { //icc | 62 if (FLAGS_type[0][1] == 'c') { //icc |
| 63 return fuzz_icc(bytes.get()); | 63 return fuzz_icc(bytes); |
| 64 } | 64 } |
| 65 // We only allow one degree of freedom to avoid a search space e
xplosion for afl-fuzz. | 65 // We only allow one degree of freedom to avoid a search space e
xplosion for afl-fuzz. |
| 66 if (FLAGS_type[0][6] == 's') { // image_scale | 66 if (FLAGS_type[0][6] == 's') { // image_scale |
| 67 return fuzz_img(bytes.get(), option, 0); | 67 return fuzz_img(bytes, option, 0); |
| 68 } | 68 } |
| 69 // image_mode | 69 // image_mode |
| 70 return fuzz_img(bytes.get(), 0, option); | 70 return fuzz_img(bytes, 0, option); |
| 71 case 's': return fuzz_skp(bytes.get()); | 71 case 's': return fuzz_skp(bytes); |
| 72 } | 72 } |
| 73 } | 73 } |
| 74 return printUsage(argv[0]); | 74 return printUsage(argv[0]); |
| 75 } | 75 } |
| 76 | 76 |
| 77 // This adds up the first 1024 bytes and returns it as an 8 bit integer. This a
llows afl-fuzz to | 77 // This adds up the first 1024 bytes and returns it as an 8 bit integer. This a
llows afl-fuzz to |
| 78 // deterministically excercise different paths, or *options* (such as different
scaling sizes or | 78 // deterministically excercise different paths, or *options* (such as different
scaling sizes or |
| 79 // different image modes) without needing to introduce a parameter. This way we
don't need a | 79 // different image modes) without needing to introduce a parameter. This way we
don't need a |
| 80 // image_scale1, image_scale2, image_scale4, etc fuzzer, we can just have a imag
e_scale fuzzer. | 80 // image_scale1, image_scale2, image_scale4, etc fuzzer, we can just have a imag
e_scale fuzzer. |
| 81 // Clients are expected to transform this number into a different range, e.g. wi
th modulo (%). | 81 // Clients are expected to transform this number into a different range, e.g. wi
th modulo (%). |
| 82 static uint8_t calculate_option(SkData* bytes) { | 82 static uint8_t calculate_option(SkData* bytes) { |
| 83 uint8_t total = 0; | 83 uint8_t total = 0; |
| 84 const uint8_t* data = bytes->bytes(); | 84 const uint8_t* data = bytes->bytes(); |
| 85 for (size_t i = 0; i < 1024 && i < bytes->size(); i++) { | 85 for (size_t i = 0; i < 1024 && i < bytes->size(); i++) { |
| 86 total += data[i]; | 86 total += data[i]; |
| 87 } | 87 } |
| 88 return total; | 88 return total; |
| 89 } | 89 } |
| 90 | 90 |
| 91 int fuzz_api(SkData* bytes) { | 91 int fuzz_api(sk_sp<SkData> bytes) { |
| 92 const char* name = FLAGS_name.isEmpty() ? "" : FLAGS_name[0]; | 92 const char* name = FLAGS_name.isEmpty() ? "" : FLAGS_name[0]; |
| 93 | 93 |
| 94 for (auto r = SkTRegistry<Fuzzable>::Head(); r; r = r->next()) { | 94 for (auto r = SkTRegistry<Fuzzable>::Head(); r; r = r->next()) { |
| 95 auto fuzzable = r->factory(); | 95 auto fuzzable = r->factory(); |
| 96 if (0 == strcmp(name, fuzzable.name)) { | 96 if (0 == strcmp(name, fuzzable.name)) { |
| 97 SkDebugf("Fuzzing %s...\n", fuzzable.name); | 97 SkDebugf("Fuzzing %s...\n", fuzzable.name); |
| 98 Fuzz fuzz(bytes); | 98 Fuzz fuzz(bytes); |
| 99 fuzzable.fn(&fuzz); | 99 fuzzable.fn(&fuzz); |
| 100 SkDebugf("[terminated] Success!\n"); | 100 SkDebugf("[terminated] Success!\n"); |
| 101 return 0; | 101 return 0; |
| 102 } | 102 } |
| 103 } | 103 } |
| 104 | 104 |
| 105 SkDebugf("When using --type api, please choose an API to fuzz with --name/-n
:\n"); | 105 SkDebugf("When using --type api, please choose an API to fuzz with --name/-n
:\n"); |
| 106 for (auto r = SkTRegistry<Fuzzable>::Head(); r; r = r->next()) { | 106 for (auto r = SkTRegistry<Fuzzable>::Head(); r; r = r->next()) { |
| 107 auto fuzzable = r->factory(); | 107 auto fuzzable = r->factory(); |
| 108 SkDebugf("\t%s\n", fuzzable.name); | 108 SkDebugf("\t%s\n", fuzzable.name); |
| 109 } | 109 } |
| 110 return 1; | 110 return 1; |
| 111 } | 111 } |
| 112 | 112 |
| 113 static void dump_png(SkBitmap bitmap) { | 113 static void dump_png(SkBitmap bitmap) { |
| 114 if (!FLAGS_dump.isEmpty()) { | 114 if (!FLAGS_dump.isEmpty()) { |
| 115 SkImageEncoder::EncodeFile(FLAGS_dump[0], bitmap, SkImageEncoder::kPNG_T
ype, 100); | 115 SkImageEncoder::EncodeFile(FLAGS_dump[0], bitmap, SkImageEncoder::kPNG_T
ype, 100); |
| 116 SkDebugf("Dumped to %s\n", FLAGS_dump[0]); | 116 SkDebugf("Dumped to %s\n", FLAGS_dump[0]); |
| 117 } | 117 } |
| 118 } | 118 } |
| 119 | 119 |
| 120 int fuzz_img(SkData* bytes, uint8_t scale, uint8_t mode) { | 120 int fuzz_img(sk_sp<SkData> bytes, uint8_t scale, uint8_t mode) { |
| 121 // We can scale 1x, 2x, 4x, 8x, 16x | 121 // We can scale 1x, 2x, 4x, 8x, 16x |
| 122 scale = scale % 5; | 122 scale = scale % 5; |
| 123 float fscale = (float)pow(2.0f, scale); | 123 float fscale = (float)pow(2.0f, scale); |
| 124 SkDebugf("Scaling factor: %f\n", fscale); | 124 SkDebugf("Scaling factor: %f\n", fscale); |
| 125 | 125 |
| 126 // We have 4 different modes of decoding, just like DM. | 126 // We have 4 different modes of decoding, just like DM. |
| 127 mode = mode % 4; | 127 mode = mode % 4; |
| 128 SkDebugf("Mode: %d\n", mode); | 128 SkDebugf("Mode: %d\n", mode); |
| 129 | 129 |
| 130 // This is mostly copied from DMSrcSink's CodecSrc::draw method. | 130 // This is mostly copied from DMSrcSink's CodecSrc::draw method. |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 break; | 353 break; |
| 354 } | 354 } |
| 355 default: | 355 default: |
| 356 SkDebugf("[terminated] Mode not implemented yet\n"); | 356 SkDebugf("[terminated] Mode not implemented yet\n"); |
| 357 } | 357 } |
| 358 | 358 |
| 359 dump_png(bitmap); | 359 dump_png(bitmap); |
| 360 return 0; | 360 return 0; |
| 361 } | 361 } |
| 362 | 362 |
| 363 int fuzz_skp(SkData* bytes) { | 363 int fuzz_skp(sk_sp<SkData> bytes) { |
| 364 SkMemoryStream stream(bytes); | 364 SkMemoryStream stream(bytes); |
| 365 SkDebugf("Decoding\n"); | 365 SkDebugf("Decoding\n"); |
| 366 sk_sp<SkPicture> pic(SkPicture::MakeFromStream(&stream)); | 366 sk_sp<SkPicture> pic(SkPicture::MakeFromStream(&stream)); |
| 367 if (!pic) { | 367 if (!pic) { |
| 368 SkDebugf("[terminated] Couldn't decode as a picture.\n"); | 368 SkDebugf("[terminated] Couldn't decode as a picture.\n"); |
| 369 return 3; | 369 return 3; |
| 370 } | 370 } |
| 371 SkDebugf("Rendering\n"); | 371 SkDebugf("Rendering\n"); |
| 372 SkBitmap bitmap; | 372 SkBitmap bitmap; |
| 373 if (!FLAGS_dump.isEmpty()) { | 373 if (!FLAGS_dump.isEmpty()) { |
| 374 SkIRect size = pic->cullRect().roundOut(); | 374 SkIRect size = pic->cullRect().roundOut(); |
| 375 bitmap.allocN32Pixels(size.width(), size.height()); | 375 bitmap.allocN32Pixels(size.width(), size.height()); |
| 376 } | 376 } |
| 377 SkCanvas canvas(bitmap); | 377 SkCanvas canvas(bitmap); |
| 378 canvas.drawPicture(pic); | 378 canvas.drawPicture(pic); |
| 379 SkDebugf("[terminated] Success! Decoded and rendered an SkPicture!\n"); | 379 SkDebugf("[terminated] Success! Decoded and rendered an SkPicture!\n"); |
| 380 dump_png(bitmap); | 380 dump_png(bitmap); |
| 381 return 0; | 381 return 0; |
| 382 } | 382 } |
| 383 | 383 |
| 384 int fuzz_icc(SkData* bytes) { | 384 int fuzz_icc(sk_sp<SkData> bytes) { |
| 385 sk_sp<SkColorSpace> space(SkColorSpace::NewICC(bytes->data(), bytes->size())
); | 385 sk_sp<SkColorSpace> space(SkColorSpace::NewICC(bytes->data(), bytes->size())
); |
| 386 if (!space) { | 386 if (!space) { |
| 387 SkDebugf("[terminated] Couldn't decode ICC.\n"); | 387 SkDebugf("[terminated] Couldn't decode ICC.\n"); |
| 388 return 1; | 388 return 1; |
| 389 } | 389 } |
| 390 SkDebugf("[terminated] Success! Decoded ICC.\n"); | 390 SkDebugf("[terminated] Success! Decoded ICC.\n"); |
| 391 return 0; | 391 return 0; |
| 392 } | 392 } |
| 393 | 393 |
| 394 int fuzz_color_deserialize(SkData* bytes) { | 394 int fuzz_color_deserialize(sk_sp<SkData> bytes) { |
| 395 sk_sp<SkColorSpace> space(SkColorSpace::Deserialize(bytes->data(), bytes->si
ze())); | 395 sk_sp<SkColorSpace> space(SkColorSpace::Deserialize(bytes->data(), bytes->si
ze())); |
| 396 if (!space) { | 396 if (!space) { |
| 397 SkDebugf("[terminated] Couldn't deserialize Colorspace.\n"); | 397 SkDebugf("[terminated] Couldn't deserialize Colorspace.\n"); |
| 398 return 1; | 398 return 1; |
| 399 } | 399 } |
| 400 SkDebugf("[terminated] Success! deserialized Colorspace.\n"); | 400 SkDebugf("[terminated] Success! deserialized Colorspace.\n"); |
| 401 return 0; | 401 return 0; |
| 402 } | 402 } |
| 403 | 403 |
| 404 Fuzz::Fuzz(SkData* bytes) : fBytes(SkSafeRef(bytes)), fNextByte(0) {} | 404 Fuzz::Fuzz(sk_sp<SkData> bytes) : fBytes(bytes), fNextByte(0) {} |
| 405 | 405 |
| 406 void Fuzz::signalBug () { SkDebugf("Signal bug\n"); raise(SIGSEGV); } | 406 void Fuzz::signalBug () { SkDebugf("Signal bug\n"); raise(SIGSEGV); } |
| 407 void Fuzz::signalBoring() { SkDebugf("Signal boring\n"); exit(0); } | 407 void Fuzz::signalBoring() { SkDebugf("Signal boring\n"); exit(0); } |
| 408 | 408 |
| 409 size_t Fuzz::size() { return fBytes->size(); } | 409 size_t Fuzz::size() { return fBytes->size(); } |
| 410 | 410 |
| 411 size_t Fuzz::remaining() { | 411 size_t Fuzz::remaining() { |
| 412 return fBytes->size() - fNextByte; | 412 return fBytes->size() - fNextByte; |
| 413 } | 413 } |
| 414 | 414 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 452 if (min > max) { | 452 if (min > max) { |
| 453 SkDebugf("Check mins and maxes (%f, %f)\n", min, max); | 453 SkDebugf("Check mins and maxes (%f, %f)\n", min, max); |
| 454 this->signalBoring(); | 454 this->signalBoring(); |
| 455 } | 455 } |
| 456 float f = std::abs(this->nextF()); | 456 float f = std::abs(this->nextF()); |
| 457 if (!std::isnormal(f) && f != 0.0) { | 457 if (!std::isnormal(f) && f != 0.0) { |
| 458 this->signalBoring(); | 458 this->signalBoring(); |
| 459 } | 459 } |
| 460 return min + fmod(f, (max - min + 1)); | 460 return min + fmod(f, (max - min + 1)); |
| 461 } | 461 } |
| OLD | NEW |