Skip to content

Commit a7760d0

Browse files
committed
Defang MacOS & iOS crashing text sequences
[Manish Goregaokar](https://manishearth.github.io/blog/2018/02/15/picking-apart-the-crashing-ios-string/) says > So, ultimately, the full set of cases that cause the crash are: > Any sequence <consonant1, virama, consonant2, ZWNJ, vowel> > in Devanagari, Bengali, and Telugu, where: ... We eliminate the ZWNJ which seems the minimally damaging thing to do to Telugu rendering per the article above: > a ZWNJ before a vowel doesn’t really do anything for most Indic scripts. This is needed as of February 2018, but hopefully not long after that.
1 parent 79c46d2 commit a7760d0

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

src/main/java/org/owasp/html/Encoding.java

+37
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,43 @@ private static void encodeHtmlOnto(
203203
output.append(plainText, pos, i).append(repl);
204204
pos = i + 1;
205205
}
206+
} else if ((0x93A <= ch && ch <= 0xC4C)
207+
&& (
208+
// Devanagari vowel
209+
ch <= 0x94F
210+
|| 0x93A <= ch && ch <= 0x94F
211+
// Benagli vowels
212+
|| 0x985 <= ch && ch <= 0x994
213+
|| 0x9BE <= ch && ch < 0x9CC // 0x9CC (Bengali AU) is ok
214+
|| 0x9E0 <= ch && ch <= 0x9E3
215+
// Telugu vowels
216+
|| 0xC05 <= ch && ch <= 0xC14
217+
|| 0xC3E <= ch && ch != 0xC48 /* 0xC48 (Telugu AI) is ok */)) {
218+
// https://manishearth.github.io/blog/2018/02/15/picking-apart-the-crashing-ios-string/
219+
// > So, ultimately, the full set of cases that cause the crash are:
220+
// > Any sequence <consonant1, virama, consonant2, ZWNJ, vowel>
221+
// > in Devanagari, Bengali, and Telugu, where: ...
222+
223+
// TODO: This is needed as of February 2018, but hopefully not long after that.
224+
// We eliminate the ZWNJ which seems the minimally damaging thing to do to
225+
// Telugu rendering per the article above:
226+
// > a ZWNJ before a vowel doesn’t really do anything for most Indic scripts.
227+
228+
if (pos < i) {
229+
if (plainText.charAt(i - 1) == 0x200C /* ZWNJ */) {
230+
output.append(plainText, pos, i - 1);
231+
// Drop the ZWNJ on the floor.
232+
pos = i;
233+
}
234+
} else if (output instanceof StringBuilder) {
235+
StringBuilder sb = (StringBuilder) output;
236+
int len = sb.length();
237+
if (len != 0) {
238+
if (sb.charAt(len - 1) == 0x200C /* ZWNJ */) {
239+
sb.setLength(len - 1);
240+
}
241+
}
242+
}
206243
} else if (((char) 0xd800) <= ch) {
207244
if (ch <= ((char) 0xdfff)) {
208245
char next;

src/test/java/org/owasp/html/HtmlSanitizerTest.java

+48
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,54 @@ public static final void testDuplicateAttributes() {
366366

367367
}
368368

369+
@Test
370+
public static final void testMacOSAndIOSQueryOfDeath() {
371+
// https://manishearth.github.io/blog/2018/02/15/picking-apart-the-crashing-ios-string/
372+
String[][] tests = {
373+
{
374+
"\u0C1C\u0C4D\u0C1E\u200C\u0C3E",
375+
"\u0C1C\u0C4D\u0C1E\u0C3E",
376+
},
377+
{
378+
"\u09B8\u09CD\u09B0<interrupted>\u200C\u09C1",
379+
"\u09B8\u09CD\u09B0\u09C1",
380+
},
381+
{
382+
"\u0C1C\u0C4D\u0C1E\u200C\u0C3E",
383+
"\u0C1C\u0C4D\u0C1E\u0C3E",
384+
},
385+
{
386+
"\u09B8\u09CD\u09B0\u200C<interrupted>\u09C1",
387+
"\u09B8\u09CD\u09B0\u09C1",
388+
},
389+
{
390+
"&#x0C1C;&#x0C4D;&#x0C1E;&#x200C;&#x0C3E;",
391+
"\u0C1C\u0C4D\u0C1E\u0C3E",
392+
},
393+
{
394+
"&#x0C1C;&#x0C4D;&#x0C1E;<interrupted>&#x200C;&#x0C3E;",
395+
"\u0C1C\u0C4D\u0C1E\u0C3E",
396+
},
397+
{
398+
"&#x09B8;&#x09CD;&#x09B0;&#x200C;&#x09C1;",
399+
"\u09B8\u09CD\u09B0\u09C1",
400+
},
401+
{
402+
"&#x09B8;&#x09CD;&#x09B0;&#x200C;<interrupted>&#x09C1;",
403+
"\u09B8\u09CD\u09B0\u09C1",
404+
},
405+
{
406+
"\u0915\u094D\u0930\u200C\u093E",
407+
"\u0915\u094D\u0930\u093E",
408+
},
409+
};
410+
411+
for (int i = 0, n = tests.length; i < n; ++i) {
412+
String[] test = tests[i];
413+
assertEquals(i + " : " + test[0], test[1], sanitize(test[0]));
414+
}
415+
}
416+
369417
private static String sanitize(@Nullable String html) {
370418
StringBuilder sb = new StringBuilder();
371419
HtmlStreamRenderer renderer = HtmlStreamRenderer.create(

0 commit comments

Comments
 (0)