libpng_read_fuzzer.cc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // libpng_read_fuzzer.cc
  2. // Copyright 2017-2018 Glenn Randers-Pehrson
  3. // Copyright 2015 The Chromium Authors. All rights reserved.
  4. // Use of this source code is governed by a BSD-style license that may
  5. // be found in the LICENSE file https://cs.chromium.org/chromium/src/LICENSE
  6. // Last changed in libpng 1.6.35 [July 15, 2018]
  7. // The modifications in 2017 by Glenn Randers-Pehrson include
  8. // 1. addition of a PNG_CLEANUP macro,
  9. // 2. setting the option to ignore ADLER32 checksums,
  10. // 3. adding "#include <string.h>" which is needed on some platforms
  11. // to provide memcpy().
  12. // 4. adding read_end_info() and creating an end_info structure.
  13. // 5. adding calls to png_set_*() transforms commonly used by browsers.
  14. #include <stddef.h>
  15. #include <stdint.h>
  16. #include <string.h>
  17. #include <vector>
  18. #define PNG_INTERNAL
  19. #include "png.h"
  20. #define PNG_CLEANUP \
  21. if(png_handler.png_ptr) \
  22. { \
  23. if (png_handler.row_ptr) \
  24. png_free(png_handler.png_ptr, png_handler.row_ptr); \
  25. if (png_handler.end_info_ptr) \
  26. png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\
  27. &png_handler.end_info_ptr); \
  28. else if (png_handler.info_ptr) \
  29. png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\
  30. nullptr); \
  31. else \
  32. png_destroy_read_struct(&png_handler.png_ptr, nullptr, nullptr); \
  33. png_handler.png_ptr = nullptr; \
  34. png_handler.row_ptr = nullptr; \
  35. png_handler.info_ptr = nullptr; \
  36. png_handler.end_info_ptr = nullptr; \
  37. }
  38. struct BufState {
  39. const uint8_t* data;
  40. size_t bytes_left;
  41. };
  42. struct PngObjectHandler {
  43. png_infop info_ptr = nullptr;
  44. png_structp png_ptr = nullptr;
  45. png_infop end_info_ptr = nullptr;
  46. png_voidp row_ptr = nullptr;
  47. BufState* buf_state = nullptr;
  48. ~PngObjectHandler() {
  49. if (row_ptr)
  50. png_free(png_ptr, row_ptr);
  51. if (end_info_ptr)
  52. png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr);
  53. else if (info_ptr)
  54. png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
  55. else
  56. png_destroy_read_struct(&png_ptr, nullptr, nullptr);
  57. delete buf_state;
  58. }
  59. };
  60. void user_read_data(png_structp png_ptr, png_bytep data, size_t length) {
  61. BufState* buf_state = static_cast<BufState*>(png_get_io_ptr(png_ptr));
  62. if (length > buf_state->bytes_left) {
  63. png_error(png_ptr, "read error");
  64. }
  65. memcpy(data, buf_state->data, length);
  66. buf_state->bytes_left -= length;
  67. buf_state->data += length;
  68. }
  69. static const int kPngHeaderSize = 8;
  70. // Entry point for LibFuzzer.
  71. // Roughly follows the libpng book example:
  72. // http://www.libpng.org/pub/png/book/chapter13.html
  73. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  74. if (size < kPngHeaderSize) {
  75. return 0;
  76. }
  77. std::vector<unsigned char> v(data, data + size);
  78. if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) {
  79. // not a PNG.
  80. return 0;
  81. }
  82. PngObjectHandler png_handler;
  83. png_handler.png_ptr = nullptr;
  84. png_handler.row_ptr = nullptr;
  85. png_handler.info_ptr = nullptr;
  86. png_handler.end_info_ptr = nullptr;
  87. png_handler.png_ptr = png_create_read_struct
  88. (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
  89. if (!png_handler.png_ptr) {
  90. return 0;
  91. }
  92. png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr);
  93. if (!png_handler.info_ptr) {
  94. PNG_CLEANUP
  95. return 0;
  96. }
  97. png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr);
  98. if (!png_handler.end_info_ptr) {
  99. PNG_CLEANUP
  100. return 0;
  101. }
  102. png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
  103. #ifdef PNG_IGNORE_ADLER32
  104. png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON);
  105. #endif
  106. // Setting up reading from buffer.
  107. png_handler.buf_state = new BufState();
  108. png_handler.buf_state->data = data + kPngHeaderSize;
  109. png_handler.buf_state->bytes_left = size - kPngHeaderSize;
  110. png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data);
  111. png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize);
  112. if (setjmp(png_jmpbuf(png_handler.png_ptr))) {
  113. PNG_CLEANUP
  114. return 0;
  115. }
  116. // Reading.
  117. png_read_info(png_handler.png_ptr, png_handler.info_ptr);
  118. // reset error handler to put png_deleter into scope.
  119. if (setjmp(png_jmpbuf(png_handler.png_ptr))) {
  120. PNG_CLEANUP
  121. return 0;
  122. }
  123. png_uint_32 width, height;
  124. int bit_depth, color_type, interlace_type, compression_type;
  125. int filter_type;
  126. if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width,
  127. &height, &bit_depth, &color_type, &interlace_type,
  128. &compression_type, &filter_type)) {
  129. PNG_CLEANUP
  130. return 0;
  131. }
  132. // This is going to be too slow.
  133. if (width && height > 100000000 / width) {
  134. PNG_CLEANUP
  135. return 0;
  136. }
  137. // Set several transforms that browsers typically use:
  138. png_set_gray_to_rgb(png_handler.png_ptr);
  139. png_set_expand(png_handler.png_ptr);
  140. png_set_packing(png_handler.png_ptr);
  141. png_set_scale_16(png_handler.png_ptr);
  142. png_set_tRNS_to_alpha(png_handler.png_ptr);
  143. int passes = png_set_interlace_handling(png_handler.png_ptr);
  144. png_read_update_info(png_handler.png_ptr, png_handler.info_ptr);
  145. png_handler.row_ptr = png_malloc(
  146. png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr,
  147. png_handler.info_ptr));
  148. for (int pass = 0; pass < passes; ++pass) {
  149. for (png_uint_32 y = 0; y < height; ++y) {
  150. png_read_row(png_handler.png_ptr,
  151. static_cast<png_bytep>(png_handler.row_ptr), nullptr);
  152. }
  153. }
  154. png_read_end(png_handler.png_ptr, png_handler.end_info_ptr);
  155. PNG_CLEANUP
  156. return 0;
  157. }