Author: markt
Date: Sat Mar  2 20:17:28 2013
New Revision: 1451933

URL: http://svn.apache.org/r1451933
Log:
Expand UTF-8 tests based on a test case written by Joe Orton for CVE-2008-2938
Note the additional failures this generates are not exploitable. They are 
invalid only because they encode a valid code point in too many bytes.

Modified:
    tomcat/trunk/java/org/apache/tomcat/websocket/Utf8Decoder.java
    tomcat/trunk/test/org/apache/tomcat/websocket/TestUtf8.java

Modified: tomcat/trunk/java/org/apache/tomcat/websocket/Utf8Decoder.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/Utf8Decoder.java?rev=1451933&r1=1451932&r2=1451933&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/Utf8Decoder.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/Utf8Decoder.java Sat Mar  2 
20:17:28 2013
@@ -169,13 +169,31 @@ public class Utf8Decoder extends Charset
                     return CoderResult.malformedForLength(1);
                 }
                 if (inIndexLimit - inIndex < 1 + tail) {
-                    // Apache Tomcat added test - detects invalid sequence as
+                    // Apache Tomcat added tests - detect invalid sequences as
                     // early as possible
                     if (jchar == 0x74 && inIndexLimit > inIndex + 1) {
                         if ((bArr[inIndex + 1] & 0xFF) > 0x8F) {
+                            // 11110100 1yyyxxxx xxxxxxxx xxxxxxxx
+                            // Any non-zero y is > max code point
                             return CoderResult.unmappableForLength(4);
                         }
                     }
+                    if (jchar == 0x60 && inIndexLimit > inIndex +1) {
+                        if ((bArr[inIndex + 1] & 0x7F) == 0) {
+                            // 11100000 10000000 10xxxxxx
+                            // should have been
+                            // 00xxxxxx
+                            return CoderResult.malformedForLength(3);
+                        }
+                    }
+                    if (jchar == 0x70 && inIndexLimit > inIndex +1) {
+                        if ((bArr[inIndex + 1] & 0x7F) < 0x10) {
+                            // 11110000 1000zzzz 1oyyyyyy 1oxxxxxx
+                            // should have been
+                            // 111ozzzz 1oyyyyyy 1oxxxxxx
+                            return CoderResult.malformedForLength(4);
+                        }
+                    }
                     break;
                 }
                 for (int i = 0; i < tail; i++) {

Modified: tomcat/trunk/test/org/apache/tomcat/websocket/TestUtf8.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/websocket/TestUtf8.java?rev=1451933&r1=1451932&r2=1451933&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/websocket/TestUtf8.java (original)
+++ tomcat/trunk/test/org/apache/tomcat/websocket/TestUtf8.java Sat Mar  2 
20:17:28 2013
@@ -38,6 +38,56 @@ public class TestUtf8 {
     private static final byte[] SRC_BYTES_2 =
             new byte[] {-12, -112, -128, -128};
 
+    // Various invalid UTF-8 sequences
+    private static final byte[][] MALFORMED = {
+            // One-byte sequences:
+            {(byte)0xFF },
+            {(byte)0xC0 },
+            {(byte)0x80 },
+
+            // Two-byte sequences:
+            {(byte)0xC0, (byte)0x80}, // U+0000 zero-padded
+            {(byte)0xC1, (byte)0xBF}, // U+007F zero-padded
+            {(byte)0xFF, (byte)0xFF}, // all ones
+            {(byte)0xE0, (byte)0x80}, // 111x first byte first nibble
+            {(byte)0xA0, (byte)0x80}, // 101x first byte first nibble
+            {(byte)0xC2, (byte)0x00}, // invalid second byte
+            {(byte)0xC2, (byte)0xC0}, // invalid second byte
+
+            // Three-byte sequences
+            {(byte)0xE0, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded
+            {(byte)0xE0, (byte)0x81, (byte)0xBF }, // U+007F zero-padded
+            {(byte)0xE0, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded
+            {(byte)0xFF, (byte)0xFF, (byte)0xFF }, // all ones
+            {(byte)0xF0, (byte)0x80, (byte)0x80 }, // invalid first byte
+            {(byte)0xE0, (byte)0xC0, (byte)0x80 }, // invalid second byte
+            {(byte)0xE0, (byte)0x80, (byte)0xC0 }, // invalid third byte
+
+            // Four-byte sequences
+            {(byte)0xF0, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 
zero-padded
+            {(byte)0xF0, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F 
zero-padded
+            {(byte)0xF0, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+007F 
zero-padded
+            {(byte)0xF0, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+07FF 
zero-padded
+
+            {(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF }, // all ones
+            {(byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80 }, // invalid 
first byte
+            {(byte)0xF0, (byte)0xC0, (byte)0x80, (byte)0x80 }, // invalid 
second byte
+            {(byte)0xF0, (byte)0x80, (byte)0xC0, (byte)0x80 }, // invalid 
third byte
+            {(byte)0xF0, (byte)0x80, (byte)0x80, (byte)0xC0 }, // invalid 
fourth byte
+
+            // Five-byte sequences
+            {(byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, // 
U+0000 zero-padded
+            {(byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x81, (byte)0xBF }, // 
U+007F zero-padded
+            {(byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xBF }, // 
U+07FF zero-padded
+            {(byte)0xF8, (byte)0x80, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // 
U+FFFF zero-padded
+
+            // Six-byte sequences
+            {(byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, 
(byte)0x80 }, // U+0000 zero-padded
+            {(byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x81, 
(byte)0xBF }, // U+007F zero-padded
+            {(byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x9F, 
(byte)0xBF }, // U+07FF zero-padded
+            {(byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x8F, (byte)0xBF, 
(byte)0xBF }, // U+FFFF zero-padded
+        };
+
     @Test
     public void testJvmDecoder1() {
         // This should trigger an error but currently passes. Once the JVM is
@@ -76,8 +126,17 @@ public class TestUtf8 {
             bb.compact();
         }
 
-        assertEquals(Boolean.valueOf(errorExpected), Boolean.valueOf(error));
-        assertEquals(failPosExpected, i);
+        StringBuilder ashex = new StringBuilder(src.length * 4);
+        for (int j = 0; j < src.length; j++) {
+            if (i > 0) ashex.append(' ');
+            ashex.append(Integer.toBinaryString(src[j] & 0xff));
+        }
+
+        assertEquals(ashex.toString(),
+                Boolean.valueOf(errorExpected), Boolean.valueOf(error));
+        if (failPosExpected != -1) {
+            assertEquals(failPosExpected, i);
+        }
     }
 
 
@@ -93,7 +152,7 @@ public class TestUtf8 {
     }
 
 
-    public void doHarmonyDecoder(byte[] src, boolean errorExpected,
+    private void doHarmonyDecoder(byte[] src, boolean errorExpected,
             int failPosExpected) {
         CharsetDecoder decoder = new Utf8Decoder();
 
@@ -113,7 +172,37 @@ public class TestUtf8 {
             bb.compact();
         }
 
-        assertEquals(Boolean.valueOf(errorExpected), Boolean.valueOf(error));
-        assertEquals(failPosExpected, i);
+        StringBuilder ashex = new StringBuilder(src.length * 4);
+        for (int j = 0; j < src.length; j++) {
+            if (i > 0) ashex.append(' ');
+            ashex.append(Integer.toBinaryString(src[j] & 0xff));
+        }
+
+        assertEquals(ashex.toString(),
+                Boolean.valueOf(errorExpected), Boolean.valueOf(error));
+        if (failPosExpected != -1) {
+            assertEquals(failPosExpected, i);
+        }
+    }
+
+
+    @Test
+    public void testUtf8MalformedJvm() {
+        for (int i = 0 ; i < MALFORMED.length; i++) {
+            // Known failures
+            if (i == 1 || i == 6 || i == 14 | i == 22) {
+                doJvmDecoder(MALFORMED[i], false, -1);
+            } else {
+                doJvmDecoder(MALFORMED[i], true, -1);
+            }
+        }
+    }
+
+
+    @Test
+    public void testUtf8MalformedHarmony() {
+        for (byte[] input : MALFORMED) {
+            doHarmonyDecoder(input, true, -1);
+        }
     }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to