CVE-2017-7867_CVE-2017-7868.patch 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. Index: source/test/intltest/utxttest.h
  2. ===================================================================
  3. --- source/test/intltest/utxttest.h (revision 39670)
  4. +++ source/test/intltest/utxttest.h (revision 39671)
  5. @@ -38,6 +38,7 @@
  6. void Ticket10562();
  7. void Ticket10983();
  8. void Ticket12130();
  9. + void Ticket12888();
  10. private:
  11. struct m { // Map between native indices & code points.
  12. Index: source/test/intltest/utxttest.cpp
  13. ===================================================================
  14. --- source/test/intltest/utxttest.cpp (revision 39670)
  15. +++ source/test/intltest/utxttest.cpp (revision 39671)
  16. @@ -67,6 +67,8 @@
  17. if (exec) Ticket10983(); break;
  18. case 7: name = "Ticket12130";
  19. if (exec) Ticket12130(); break;
  20. + case 8: name = "Ticket12888";
  21. + if (exec) Ticket12888(); break;
  22. default: name = ""; break;
  23. }
  24. }
  25. @@ -1583,3 +1585,63 @@
  26. }
  27. utext_close(&ut);
  28. }
  29. +
  30. +// Ticket 12888: bad handling of illegal utf-8 containing many instances of the archaic, now illegal,
  31. +// six byte utf-8 forms. Original implementation had an assumption that
  32. +// there would be at most three utf-8 bytes per UTF-16 code unit.
  33. +// The five and six byte sequences map to a single replacement character.
  34. +
  35. +void UTextTest::Ticket12888() {
  36. + const char *badString =
  37. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  38. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  39. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  40. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  41. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  42. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  43. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  44. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  45. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  46. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  47. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  48. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  49. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  50. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  51. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  52. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  53. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  54. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  55. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"
  56. + "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80";
  57. +
  58. + UErrorCode status = U_ZERO_ERROR;
  59. + LocalUTextPointer ut(utext_openUTF8(NULL, badString, -1, &status));
  60. + TEST_SUCCESS(status);
  61. + for (;;) {
  62. + UChar32 c = utext_next32(ut.getAlias());
  63. + if (c == U_SENTINEL) {
  64. + break;
  65. + }
  66. + }
  67. + int32_t endIdx = utext_getNativeIndex(ut.getAlias());
  68. + if (endIdx != (int32_t)strlen(badString)) {
  69. + errln("%s:%d expected=%d, actual=%d", __FILE__, __LINE__, strlen(badString), endIdx);
  70. + return;
  71. + }
  72. +
  73. + for (int32_t prevIndex = endIdx; prevIndex>0;) {
  74. + UChar32 c = utext_previous32(ut.getAlias());
  75. + int32_t currentIndex = utext_getNativeIndex(ut.getAlias());
  76. + if (c != 0xfffd) {
  77. + errln("%s:%d (expected, actual, index) = (%d, %d, %d)\n",
  78. + __FILE__, __LINE__, 0xfffd, c, currentIndex);
  79. + break;
  80. + }
  81. + if (currentIndex != prevIndex - 6) {
  82. + errln("%s:%d: wrong index. Expected, actual = %d, %d",
  83. + __FILE__, __LINE__, prevIndex - 6, currentIndex);
  84. + break;
  85. + }
  86. + prevIndex = currentIndex;
  87. + }
  88. +}
  89. Index: source/common/utext.cpp
  90. ===================================================================
  91. --- source/common/utext.cpp (revision 39670)
  92. +++ source/common/utext.cpp (revision 39671)
  93. @@ -847,9 +847,15 @@
  94. //------------------------------------------------------------------------------
  95. // Chunk size.
  96. -// Must be less than 85, because of byte mapping from UChar indexes to native indexes.
  97. -// Worst case is three native bytes to one UChar. (Supplemenaries are 4 native bytes
  98. -// to two UChars.)
  99. +// Must be less than 42 (256/6), because of byte mapping from UChar indexes to native indexes.
  100. +// Worst case there are six UTF-8 bytes per UChar.
  101. +// obsolete 6 byte form fd + 5 trails maps to fffd
  102. +// obsolete 5 byte form fc + 4 trails maps to fffd
  103. +// non-shortest 4 byte forms maps to fffd
  104. +// normal supplementaries map to a pair of utf-16, two utf8 bytes per utf-16 unit
  105. +// mapToUChars array size must allow for the worst case, 6.
  106. +// This could be brought down to 4, by treating fd and fc as pure illegal,
  107. +// rather than obsolete lead bytes. But that is not compatible with the utf-8 access macros.
  108. //
  109. enum { UTF8_TEXT_CHUNK_SIZE=32 };
  110. @@ -889,7 +895,7 @@
  111. // Requires two extra slots,
  112. // one for a supplementary starting in the last normal position,
  113. // and one for an entry for the buffer limit position.
  114. - uint8_t mapToUChars[UTF8_TEXT_CHUNK_SIZE*3+6]; // Map native offset from bufNativeStart to
  115. + uint8_t mapToUChars[UTF8_TEXT_CHUNK_SIZE*6+6]; // Map native offset from bufNativeStart to
  116. // correspoding offset in filled part of buf.
  117. int32_t align;
  118. };
  119. @@ -1032,6 +1038,7 @@
  120. // Requested index is in this buffer.
  121. u8b = (UTF8Buf *)ut->p; // the current buffer
  122. mapIndex = ix - u8b->toUCharsMapStart;
  123. + U_ASSERT(mapIndex < (int32_t)sizeof(UTF8Buf::mapToUChars));
  124. ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
  125. return TRUE;
  126. @@ -1298,6 +1305,10 @@
  127. // Can only do this if the incoming index is somewhere in the interior of the string.
  128. // If index is at the end, there is no character there to look at.
  129. if (ix != ut->b) {
  130. + // Note: this function will only move the index back if it is on a trail byte
  131. + // and there is a preceding lead byte and the sequence from the lead
  132. + // through this trail could be part of a valid UTF-8 sequence
  133. + // Otherwise the index remains unchanged.
  134. U8_SET_CP_START(s8, 0, ix);
  135. }
  136. @@ -1311,7 +1322,10 @@
  137. UChar *buf = u8b->buf;
  138. uint8_t *mapToNative = u8b->mapToNative;
  139. uint8_t *mapToUChars = u8b->mapToUChars;
  140. - int32_t toUCharsMapStart = ix - (UTF8_TEXT_CHUNK_SIZE*3 + 1);
  141. + int32_t toUCharsMapStart = ix - sizeof(UTF8Buf::mapToUChars) + 1;
  142. + // Note that toUCharsMapStart can be negative. Happens when the remaining
  143. + // text from current position to the beginning is less than the buffer size.
  144. + // + 1 because mapToUChars must have a slot at the end for the bufNativeLimit entry.
  145. int32_t destIx = UTF8_TEXT_CHUNK_SIZE+2; // Start in the overflow region
  146. // at end of buffer to leave room
  147. // for a surrogate pair at the
  148. @@ -1338,6 +1352,7 @@
  149. if (c<0x80) {
  150. // Special case ASCII range for speed.
  151. buf[destIx] = (UChar)c;
  152. + U_ASSERT(toUCharsMapStart <= srcIx);
  153. mapToUChars[srcIx - toUCharsMapStart] = (uint8_t)destIx;
  154. mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart);
  155. } else {
  156. @@ -1367,6 +1382,7 @@
  157. do {
  158. mapToUChars[sIx-- - toUCharsMapStart] = (uint8_t)destIx;
  159. } while (sIx >= srcIx);
  160. + U_ASSERT(toUCharsMapStart <= (srcIx+1));
  161. // Set native indexing limit to be the current position.
  162. // We are processing a non-ascii, non-native-indexing char now;
  163. @@ -1541,6 +1557,7 @@
  164. U_ASSERT(index>=ut->chunkNativeStart+ut->nativeIndexingLimit);
  165. U_ASSERT(index<=ut->chunkNativeLimit);
  166. int32_t mapIndex = index - u8b->toUCharsMapStart;
  167. + U_ASSERT(mapIndex < (int32_t)sizeof(UTF8Buf::mapToUChars));
  168. int32_t offset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
  169. U_ASSERT(offset>=0 && offset<=ut->chunkLength);
  170. return offset;